Merge "Native Side of Binder Proxy Tracking by Uid"
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 49ff460..75ad5d5 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 @@
 
 // ---------------------------------------------------------------------------
 
+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 @@
 
 // ---------------------------------------------------------------------------
 
-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 @@
 
     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 @@
     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 c8cdb77..53f8ddd 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -288,7 +288,7 @@
                    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 @@
         // 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 7ef93aa..8bd297b 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 @@
             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 @@
     };
 
 protected:
+                        BpBinder(int32_t handle,int32_t trackedUid);
     virtual             ~BpBinder();
     virtual void        onFirstRef();
     virtual void        onLastStrongRef(const void* id);
@@ -115,6 +129,16 @@
             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