Loading libs/binder/BpBinder.cpp +109 −1 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <binder/IPCThreadState.h> #include <binder/IResultReceiver.h> #include <cutils/compiler.h> #include <utils/Log.h> #include <stdio.h> Loading @@ -32,6 +33,23 @@ namespace android { // --------------------------------------------------------------------------- Mutex BpBinder::sTrackingLock; std::unordered_map<int32_t,uint32_t> BpBinder::sTrackingMap; int BpBinder::sNumTrackedUids = 0; std::atomic_bool BpBinder::sCountByUidEnabled(false); binder_proxy_limit_callback BpBinder::sLimitCallback; bool BpBinder::sBinderProxyThrottleCreate = false; // Arbitrarily high value that probably distinguishes a bad behaving app uint32_t BpBinder::sBinderProxyCountHighWatermark = 2500; // Another arbitrary value a binder count needs to drop below before another callback will be called uint32_t BpBinder::sBinderProxyCountLowWatermark = 2000; enum { CALLBACK_TRIGGERED_MASK = 0x80000000, // A flag denoting that the callback has been called COUNTING_VALUE_MASK = 0x7FFFFFFF, // A mask of the remaining bits for the count value }; BpBinder::ObjectManager::ObjectManager() { } Loading Loading @@ -87,11 +105,47 @@ void BpBinder::ObjectManager::kill() // --------------------------------------------------------------------------- BpBinder::BpBinder(int32_t handle) BpBinder* BpBinder::create(int32_t handle) { int32_t trackedUid = -1; if (sCountByUidEnabled) { BpBinder* out; trackedUid = IPCThreadState::self()->getCallingUid(); AutoMutex _l(sTrackingLock); if ((sTrackingMap[trackedUid] & COUNTING_VALUE_MASK) >= sBinderProxyCountHighWatermark) { ALOGE("Too many binder proxy objects sent to uid %d from uid %d (over %d proxies held)", getuid(), trackedUid, sBinderProxyCountHighWatermark); if (sBinderProxyThrottleCreate) { ALOGE("Returning Null Binder Proxy Object to uid %d", trackedUid); out = nullptr; } else { // increment and construct here in case callback has an async kill causing a race sTrackingMap[trackedUid]++; out = new BpBinder(handle, trackedUid); } if (sLimitCallback && !(sTrackingMap[trackedUid] & CALLBACK_TRIGGERED_MASK)) { sTrackingMap[trackedUid] |= CALLBACK_TRIGGERED_MASK; sLimitCallback(trackedUid); } } else { sTrackingMap[trackedUid]++; out = new BpBinder(handle, trackedUid); } return out; } else { return new BpBinder(handle, trackedUid); } } BpBinder::BpBinder(int32_t handle, int32_t trackedUid) : mHandle(handle) , mAlive(1) , mObitsSent(0) , mObituaries(NULL) , mTrackedUid(trackedUid) { ALOGV("Creating BpBinder %p handle %d\n", this, mHandle); Loading Loading @@ -315,6 +369,24 @@ BpBinder::~BpBinder() IPCThreadState* ipc = IPCThreadState::self(); if (mTrackedUid >= 0) { AutoMutex _l(sTrackingLock); if (CC_UNLIKELY(sTrackingMap[mTrackedUid] == 0)) { ALOGE("Unexpected Binder Proxy tracking decrement in %p handle %d\n", this, mHandle); } else { if (CC_UNLIKELY( (sTrackingMap[mTrackedUid] & CALLBACK_TRIGGERED_MASK) && ((sTrackingMap[mTrackedUid] & COUNTING_VALUE_MASK) <= sBinderProxyCountLowWatermark) )) { // Clear the Callback Triggered bit when crossing below the low watermark sTrackingMap[mTrackedUid] &= ~CALLBACK_TRIGGERED_MASK; } if (--sTrackingMap[mTrackedUid] == 0) { sTrackingMap.erase(mTrackedUid); } } } mLock.lock(); Vector<Obituary>* obits = mObituaries; if(obits != NULL) { Loading Loading @@ -360,6 +432,42 @@ bool BpBinder::onIncStrongAttempted(uint32_t /*flags*/, const void* /*id*/) return ipc ? ipc->attemptIncStrongHandle(mHandle) == NO_ERROR : false; } uint32_t BpBinder::getBinderProxyCount(uint32_t uid) { AutoMutex _l(sTrackingLock); auto it = sTrackingMap.find(uid); if (it != sTrackingMap.end()) { return it->second & COUNTING_VALUE_MASK; } return 0; } void BpBinder::getCountByUid(Vector<uint32_t>& uids, Vector<uint32_t>& counts) { AutoMutex _l(sTrackingLock); uids.setCapacity(sTrackingMap.size()); counts.setCapacity(sTrackingMap.size()); for (const auto& it : sTrackingMap) { uids.push_back(it.first); counts.push_back(it.second & COUNTING_VALUE_MASK); } } void BpBinder::enableCountByUid() { sCountByUidEnabled.store(true); } void BpBinder::disableCountByUid() { sCountByUidEnabled.store(false); } void BpBinder::setCountByUidEnabled(bool enable) { sCountByUidEnabled.store(enable); } void BpBinder::setLimitCallback(binder_proxy_limit_callback cb) { AutoMutex _l(sTrackingLock); sLimitCallback = cb; } void BpBinder::setBinderProxyCountWatermarks(int high, int low) { AutoMutex _l(sTrackingLock); sBinderProxyCountHighWatermark = high; sBinderProxyCountLowWatermark = low; } // --------------------------------------------------------------------------- }; // namespace android libs/binder/ProcessState.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -276,7 +276,7 @@ sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle) return NULL; } b = new BpBinder(handle); b = BpBinder::create(handle); e->binder = b; if (b) e->refs = b->getWeakRefs(); result = b; Loading Loading @@ -310,7 +310,7 @@ wp<IBinder> ProcessState::getWeakProxyForHandle(int32_t handle) // arriving from the driver. IBinder* b = e->binder; if (b == NULL || !e->refs->attemptIncWeak(this)) { b = new BpBinder(handle); b = BpBinder::create(handle); result = b; e->binder = b; if (b) e->refs = b->getWeakRefs(); Loading libs/binder/include/binder/BpBinder.h +25 −1 Original line number Diff line number Diff line Loading @@ -19,15 +19,20 @@ #include <binder/IBinder.h> #include <utils/KeyedVector.h> #include <utils/Mutex.h> #include <utils/threads.h> #include <unordered_map> // --------------------------------------------------------------------------- namespace android { using binder_proxy_limit_callback = void(*)(int); class BpBinder : public IBinder { public: BpBinder(int32_t handle); static BpBinder* create(int32_t handle); inline int32_t handle() const { return mHandle; } Loading Loading @@ -61,6 +66,14 @@ public: status_t setConstantData(const void* data, size_t size); void sendObituary(); static uint32_t getBinderProxyCount(uint32_t uid); static void getCountByUid(Vector<uint32_t>& uids, Vector<uint32_t>& counts); static void enableCountByUid(); static void disableCountByUid(); static void setCountByUidEnabled(bool enable); static void setLimitCallback(binder_proxy_limit_callback cb); static void setBinderProxyCountWatermarks(int high, int low); class ObjectManager { public: Loading Loading @@ -91,6 +104,7 @@ public: }; protected: BpBinder(int32_t handle,int32_t trackedUid); virtual ~BpBinder(); virtual void onFirstRef(); virtual void onLastStrongRef(const void* id); Loading @@ -115,6 +129,16 @@ private: ObjectManager mObjects; Parcel* mConstantData; mutable String16 mDescriptorCache; int32_t mTrackedUid; static Mutex sTrackingLock; static std::unordered_map<int32_t,uint32_t> sTrackingMap; static int sNumTrackedUids; static std::atomic_bool sCountByUidEnabled; static binder_proxy_limit_callback sLimitCallback; static uint32_t sBinderProxyCountHighWatermark; static uint32_t sBinderProxyCountLowWatermark; static bool sBinderProxyThrottleCreate; }; }; // namespace android Loading Loading
libs/binder/BpBinder.cpp +109 −1 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <binder/IPCThreadState.h> #include <binder/IResultReceiver.h> #include <cutils/compiler.h> #include <utils/Log.h> #include <stdio.h> Loading @@ -32,6 +33,23 @@ namespace android { // --------------------------------------------------------------------------- Mutex BpBinder::sTrackingLock; std::unordered_map<int32_t,uint32_t> BpBinder::sTrackingMap; int BpBinder::sNumTrackedUids = 0; std::atomic_bool BpBinder::sCountByUidEnabled(false); binder_proxy_limit_callback BpBinder::sLimitCallback; bool BpBinder::sBinderProxyThrottleCreate = false; // Arbitrarily high value that probably distinguishes a bad behaving app uint32_t BpBinder::sBinderProxyCountHighWatermark = 2500; // Another arbitrary value a binder count needs to drop below before another callback will be called uint32_t BpBinder::sBinderProxyCountLowWatermark = 2000; enum { CALLBACK_TRIGGERED_MASK = 0x80000000, // A flag denoting that the callback has been called COUNTING_VALUE_MASK = 0x7FFFFFFF, // A mask of the remaining bits for the count value }; BpBinder::ObjectManager::ObjectManager() { } Loading Loading @@ -87,11 +105,47 @@ void BpBinder::ObjectManager::kill() // --------------------------------------------------------------------------- BpBinder::BpBinder(int32_t handle) BpBinder* BpBinder::create(int32_t handle) { int32_t trackedUid = -1; if (sCountByUidEnabled) { BpBinder* out; trackedUid = IPCThreadState::self()->getCallingUid(); AutoMutex _l(sTrackingLock); if ((sTrackingMap[trackedUid] & COUNTING_VALUE_MASK) >= sBinderProxyCountHighWatermark) { ALOGE("Too many binder proxy objects sent to uid %d from uid %d (over %d proxies held)", getuid(), trackedUid, sBinderProxyCountHighWatermark); if (sBinderProxyThrottleCreate) { ALOGE("Returning Null Binder Proxy Object to uid %d", trackedUid); out = nullptr; } else { // increment and construct here in case callback has an async kill causing a race sTrackingMap[trackedUid]++; out = new BpBinder(handle, trackedUid); } if (sLimitCallback && !(sTrackingMap[trackedUid] & CALLBACK_TRIGGERED_MASK)) { sTrackingMap[trackedUid] |= CALLBACK_TRIGGERED_MASK; sLimitCallback(trackedUid); } } else { sTrackingMap[trackedUid]++; out = new BpBinder(handle, trackedUid); } return out; } else { return new BpBinder(handle, trackedUid); } } BpBinder::BpBinder(int32_t handle, int32_t trackedUid) : mHandle(handle) , mAlive(1) , mObitsSent(0) , mObituaries(NULL) , mTrackedUid(trackedUid) { ALOGV("Creating BpBinder %p handle %d\n", this, mHandle); Loading Loading @@ -315,6 +369,24 @@ BpBinder::~BpBinder() IPCThreadState* ipc = IPCThreadState::self(); if (mTrackedUid >= 0) { AutoMutex _l(sTrackingLock); if (CC_UNLIKELY(sTrackingMap[mTrackedUid] == 0)) { ALOGE("Unexpected Binder Proxy tracking decrement in %p handle %d\n", this, mHandle); } else { if (CC_UNLIKELY( (sTrackingMap[mTrackedUid] & CALLBACK_TRIGGERED_MASK) && ((sTrackingMap[mTrackedUid] & COUNTING_VALUE_MASK) <= sBinderProxyCountLowWatermark) )) { // Clear the Callback Triggered bit when crossing below the low watermark sTrackingMap[mTrackedUid] &= ~CALLBACK_TRIGGERED_MASK; } if (--sTrackingMap[mTrackedUid] == 0) { sTrackingMap.erase(mTrackedUid); } } } mLock.lock(); Vector<Obituary>* obits = mObituaries; if(obits != NULL) { Loading Loading @@ -360,6 +432,42 @@ bool BpBinder::onIncStrongAttempted(uint32_t /*flags*/, const void* /*id*/) return ipc ? ipc->attemptIncStrongHandle(mHandle) == NO_ERROR : false; } uint32_t BpBinder::getBinderProxyCount(uint32_t uid) { AutoMutex _l(sTrackingLock); auto it = sTrackingMap.find(uid); if (it != sTrackingMap.end()) { return it->second & COUNTING_VALUE_MASK; } return 0; } void BpBinder::getCountByUid(Vector<uint32_t>& uids, Vector<uint32_t>& counts) { AutoMutex _l(sTrackingLock); uids.setCapacity(sTrackingMap.size()); counts.setCapacity(sTrackingMap.size()); for (const auto& it : sTrackingMap) { uids.push_back(it.first); counts.push_back(it.second & COUNTING_VALUE_MASK); } } void BpBinder::enableCountByUid() { sCountByUidEnabled.store(true); } void BpBinder::disableCountByUid() { sCountByUidEnabled.store(false); } void BpBinder::setCountByUidEnabled(bool enable) { sCountByUidEnabled.store(enable); } void BpBinder::setLimitCallback(binder_proxy_limit_callback cb) { AutoMutex _l(sTrackingLock); sLimitCallback = cb; } void BpBinder::setBinderProxyCountWatermarks(int high, int low) { AutoMutex _l(sTrackingLock); sBinderProxyCountHighWatermark = high; sBinderProxyCountLowWatermark = low; } // --------------------------------------------------------------------------- }; // namespace android
libs/binder/ProcessState.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -276,7 +276,7 @@ sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle) return NULL; } b = new BpBinder(handle); b = BpBinder::create(handle); e->binder = b; if (b) e->refs = b->getWeakRefs(); result = b; Loading Loading @@ -310,7 +310,7 @@ wp<IBinder> ProcessState::getWeakProxyForHandle(int32_t handle) // arriving from the driver. IBinder* b = e->binder; if (b == NULL || !e->refs->attemptIncWeak(this)) { b = new BpBinder(handle); b = BpBinder::create(handle); result = b; e->binder = b; if (b) e->refs = b->getWeakRefs(); Loading
libs/binder/include/binder/BpBinder.h +25 −1 Original line number Diff line number Diff line Loading @@ -19,15 +19,20 @@ #include <binder/IBinder.h> #include <utils/KeyedVector.h> #include <utils/Mutex.h> #include <utils/threads.h> #include <unordered_map> // --------------------------------------------------------------------------- namespace android { using binder_proxy_limit_callback = void(*)(int); class BpBinder : public IBinder { public: BpBinder(int32_t handle); static BpBinder* create(int32_t handle); inline int32_t handle() const { return mHandle; } Loading Loading @@ -61,6 +66,14 @@ public: status_t setConstantData(const void* data, size_t size); void sendObituary(); static uint32_t getBinderProxyCount(uint32_t uid); static void getCountByUid(Vector<uint32_t>& uids, Vector<uint32_t>& counts); static void enableCountByUid(); static void disableCountByUid(); static void setCountByUidEnabled(bool enable); static void setLimitCallback(binder_proxy_limit_callback cb); static void setBinderProxyCountWatermarks(int high, int low); class ObjectManager { public: Loading Loading @@ -91,6 +104,7 @@ public: }; protected: BpBinder(int32_t handle,int32_t trackedUid); virtual ~BpBinder(); virtual void onFirstRef(); virtual void onLastStrongRef(const void* id); Loading @@ -115,6 +129,16 @@ private: ObjectManager mObjects; Parcel* mConstantData; mutable String16 mDescriptorCache; int32_t mTrackedUid; static Mutex sTrackingLock; static std::unordered_map<int32_t,uint32_t> sTrackingMap; static int sNumTrackedUids; static std::atomic_bool sCountByUidEnabled; static binder_proxy_limit_callback sLimitCallback; static uint32_t sBinderProxyCountHighWatermark; static uint32_t sBinderProxyCountLowWatermark; static bool sBinderProxyThrottleCreate; }; }; // namespace android Loading