diff options
-rw-r--r-- | libs/binder/BpBinder.cpp | 110 | ||||
-rw-r--r-- | libs/binder/ProcessState.cpp | 4 | ||||
-rw-r--r-- | libs/binder/include/binder/BpBinder.h | 26 |
3 files changed, 136 insertions, 4 deletions
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp index 49ff46033c..75ad5d51b5 100644 --- a/libs/binder/BpBinder.cpp +++ b/libs/binder/BpBinder.cpp @@ -21,6 +21,7 @@ #include <binder/IPCThreadState.h> #include <binder/IResultReceiver.h> +#include <cutils/compiler.h> #include <utils/Log.h> #include <stdio.h> @@ -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() { } @@ -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(nullptr) + , mTrackedUid(trackedUid) { ALOGV("Creating BpBinder %p handle %d\n", this, mHandle); @@ -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 != nullptr) { @@ -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 diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp index c8cdb77b9c..53f8dddfe1 100644 --- a/libs/binder/ProcessState.cpp +++ b/libs/binder/ProcessState.cpp @@ -288,7 +288,7 @@ sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle) return nullptr; } - b = new BpBinder(handle); + b = BpBinder::create(handle); e->binder = b; if (b) e->refs = b->getWeakRefs(); result = b; @@ -322,7 +322,7 @@ wp<IBinder> ProcessState::getWeakProxyForHandle(int32_t handle) // arriving from the driver. IBinder* b = e->binder; if (b == nullptr || !e->refs->attemptIncWeak(this)) { - b = new BpBinder(handle); + b = BpBinder::create(handle); result = b; e->binder = b; if (b) e->refs = b->getWeakRefs(); diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h index 7ef93aa390..8bd297bcfb 100644 --- a/libs/binder/include/binder/BpBinder.h +++ b/libs/binder/include/binder/BpBinder.h @@ -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; } @@ -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: @@ -91,6 +104,7 @@ public: }; protected: + BpBinder(int32_t handle,int32_t trackedUid); virtual ~BpBinder(); virtual void onFirstRef(); virtual void onLastStrongRef(const void* id); @@ -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 |