diff options
Diffstat (limited to 'libs/binder/BpBinder.cpp')
| -rw-r--r-- | libs/binder/BpBinder.cpp | 110 |
1 files changed, 109 insertions, 1 deletions
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp index c0e029622a..289433b0bd 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(NULL) + , 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 != NULL) { @@ -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 |