Merge changes from topic "bug_298263955_proxy_warning" into main am: ad2da357f8
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/3023864
Change-Id: I51fa78d30b1afd87aea45a5c45bde50976e70dc3
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/core/java/com/android/internal/os/BinderInternal.java b/core/java/com/android/internal/os/BinderInternal.java
index c14d8d8..8063be6 100644
--- a/core/java/com/android/internal/os/BinderInternal.java
+++ b/core/java/com/android/internal/os/BinderInternal.java
@@ -45,8 +45,8 @@
static ArrayList<Runnable> sGcWatchers = new ArrayList<>();
static Runnable[] sTmpWatchers = new Runnable[1];
static long sLastGcTime;
- static final BinderProxyLimitListenerDelegate sBinderProxyLimitListenerDelegate =
- new BinderProxyLimitListenerDelegate();
+ static final BinderProxyCountEventListenerDelegate sBinderProxyCountEventListenerDelegate =
+ new BinderProxyCountEventListenerDelegate();
static final class GcWatcher {
@Override
@@ -226,15 +226,24 @@
* @param low The threshold a binder count must drop below before the callback
* can be called again. (This is to avoid many repeated calls to the
* callback in a brief period of time)
+ * @param warning The threshold between {@code high} and {@code low} where if the binder count
+ * exceeds that, the warning callback would be triggered.
*/
- public static final native void nSetBinderProxyCountWatermarks(int high, int low);
+ public static final native void nSetBinderProxyCountWatermarks(int high, int low, int warning);
/**
* Interface for callback invocation when the Binder Proxy limit is reached. onLimitReached will
* be called with the uid of the app causing too many Binder Proxies
*/
- public interface BinderProxyLimitListener {
+ public interface BinderProxyCountEventListener {
public void onLimitReached(int uid);
+
+ /**
+ * Call when the number of binder proxies from the uid of the app reaches
+ * the warning threshold.
+ */
+ default void onWarningThresholdReached(int uid) {
+ }
}
/**
@@ -243,7 +252,17 @@
* @param uid The uid of the bad behaving app sending too many binders
*/
public static void binderProxyLimitCallbackFromNative(int uid) {
- sBinderProxyLimitListenerDelegate.notifyClient(uid);
+ sBinderProxyCountEventListenerDelegate.notifyLimitReached(uid);
+ }
+
+ /**
+ * Callback used by native code to trigger a callback in java code. The callback will be
+ * triggered when too many binder proxies from a uid hits the warning limit.
+ * @param uid The uid of the bad behaving app sending too many binders
+ */
+ @SuppressWarnings("unused")
+ public static void binderProxyWarningCallbackFromNative(int uid) {
+ sBinderProxyCountEventListenerDelegate.notifyWarningReached(uid);
}
/**
@@ -252,41 +271,45 @@
* @param handler must not be null, callback will be posted through the handler;
*
*/
- public static void setBinderProxyCountCallback(BinderProxyLimitListener listener,
+ public static void setBinderProxyCountCallback(BinderProxyCountEventListener listener,
@NonNull Handler handler) {
Preconditions.checkNotNull(handler,
"Must provide NonNull Handler to setBinderProxyCountCallback when setting "
- + "BinderProxyLimitListener");
- sBinderProxyLimitListenerDelegate.setListener(listener, handler);
+ + "BinderProxyCountEventListener");
+ sBinderProxyCountEventListenerDelegate.setListener(listener, handler);
}
/**
* Clear the Binder Proxy callback
*/
public static void clearBinderProxyCountCallback() {
- sBinderProxyLimitListenerDelegate.setListener(null, null);
+ sBinderProxyCountEventListenerDelegate.setListener(null, null);
}
- static private class BinderProxyLimitListenerDelegate {
- private BinderProxyLimitListener mBinderProxyLimitListener;
+ private static class BinderProxyCountEventListenerDelegate {
+ private BinderProxyCountEventListener mBinderProxyCountEventListener;
private Handler mHandler;
- void setListener(BinderProxyLimitListener listener, Handler handler) {
+ void setListener(BinderProxyCountEventListener listener, Handler handler) {
synchronized (this) {
- mBinderProxyLimitListener = listener;
+ mBinderProxyCountEventListener = listener;
mHandler = handler;
}
}
- void notifyClient(final int uid) {
+ void notifyLimitReached(final int uid) {
synchronized (this) {
- if (mBinderProxyLimitListener != null) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mBinderProxyLimitListener.onLimitReached(uid);
- }
- });
+ if (mBinderProxyCountEventListener != null) {
+ mHandler.post(() -> mBinderProxyCountEventListener.onLimitReached(uid));
+ }
+ }
+ }
+
+ void notifyWarningReached(final int uid) {
+ synchronized (this) {
+ if (mBinderProxyCountEventListener != null) {
+ mHandler.post(() ->
+ mBinderProxyCountEventListener.onWarningThresholdReached(uid));
}
}
}
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index d2d5186..2068bd7 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -88,6 +88,7 @@
jclass mClass;
jmethodID mForceGc;
jmethodID mProxyLimitCallback;
+ jmethodID mProxyWarningCallback;
} gBinderInternalOffsets;
@@ -1240,7 +1241,7 @@
gCollectedAtRefs = gNumLocalRefsCreated + gNumDeathRefsCreated;
}
-static void android_os_BinderInternal_proxyLimitcallback(int uid)
+static void android_os_BinderInternal_proxyLimitCallback(int uid)
{
JNIEnv *env = AndroidRuntime::getJNIEnv();
env->CallStaticVoidMethod(gBinderInternalOffsets.mClass,
@@ -1254,6 +1255,20 @@
}
}
+static void android_os_BinderInternal_proxyWarningCallback(int uid)
+{
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ env->CallStaticVoidMethod(gBinderInternalOffsets.mClass,
+ gBinderInternalOffsets.mProxyWarningCallback,
+ uid);
+
+ if (env->ExceptionCheck()) {
+ ScopedLocalRef<jthrowable> excep(env, env->ExceptionOccurred());
+ binder_report_exception(env, excep.get(),
+ "*** Uncaught exception in binderProxyWarningCallbackFromNative");
+ }
+}
+
static void android_os_BinderInternal_setBinderProxyCountEnabled(JNIEnv* env, jobject clazz,
jboolean enable)
{
@@ -1278,9 +1293,10 @@
}
static void android_os_BinderInternal_setBinderProxyCountWatermarks(JNIEnv* env, jobject clazz,
- jint high, jint low)
+ jint high, jint low,
+ jint warning)
{
- BpBinder::setBinderProxyCountWatermarks(high, low);
+ BpBinder::setBinderProxyCountWatermarks(high, low, warning);
}
// ----------------------------------------------------------------------------
@@ -1295,7 +1311,7 @@
{ "nSetBinderProxyCountEnabled", "(Z)V", (void*)android_os_BinderInternal_setBinderProxyCountEnabled },
{ "nGetBinderProxyPerUidCounts", "()Landroid/util/SparseIntArray;", (void*)android_os_BinderInternal_getBinderProxyPerUidCounts },
{ "nGetBinderProxyCount", "(I)I", (void*)android_os_BinderInternal_getBinderProxyCount },
- { "nSetBinderProxyCountWatermarks", "(II)V", (void*)android_os_BinderInternal_setBinderProxyCountWatermarks}
+ { "nSetBinderProxyCountWatermarks", "(III)V", (void*)android_os_BinderInternal_setBinderProxyCountWatermarks}
};
const char* const kBinderInternalPathName = "com/android/internal/os/BinderInternal";
@@ -1307,6 +1323,8 @@
gBinderInternalOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
gBinderInternalOffsets.mForceGc = GetStaticMethodIDOrDie(env, clazz, "forceBinderGc", "()V");
gBinderInternalOffsets.mProxyLimitCallback = GetStaticMethodIDOrDie(env, clazz, "binderProxyLimitCallbackFromNative", "(I)V");
+ gBinderInternalOffsets.mProxyWarningCallback =
+ GetStaticMethodIDOrDie(env, clazz, "binderProxyWarningCallbackFromNative", "(I)V");
jclass SparseIntArrayClass = FindClassOrDie(env, "android/util/SparseIntArray");
gSparseIntArrayOffsets.classObject = MakeGlobalRefOrDie(env, SparseIntArrayClass);
@@ -1315,7 +1333,8 @@
gSparseIntArrayOffsets.put = GetMethodIDOrDie(env, gSparseIntArrayOffsets.classObject, "put",
"(II)V");
- BpBinder::setLimitCallback(android_os_BinderInternal_proxyLimitcallback);
+ BpBinder::setBinderProxyCountEventCallback(android_os_BinderInternal_proxyLimitCallback,
+ android_os_BinderInternal_proxyWarningCallback);
return RegisterMethodsOrDie(
env, kBinderInternalPathName,
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 1a3ec27..871feb6 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -116,6 +116,8 @@
":BinderDeathRecipientHelperApp1",
":BinderDeathRecipientHelperApp2",
":com.android.cts.helpers.aosp",
+ ":BinderProxyCountingTestApp",
+ ":BinderProxyCountingTestService",
],
}
diff --git a/core/tests/coretests/AndroidTest.xml b/core/tests/coretests/AndroidTest.xml
index 05b309b..bf2a5b8 100644
--- a/core/tests/coretests/AndroidTest.xml
+++ b/core/tests/coretests/AndroidTest.xml
@@ -22,6 +22,8 @@
<option name="test-file-name" value="FrameworksCoreTests.apk" />
<option name="test-file-name" value="BinderDeathRecipientHelperApp1.apk" />
<option name="test-file-name" value="BinderDeathRecipientHelperApp2.apk" />
+ <option name="test-file-name" value="BinderProxyCountingTestApp.apk" />
+ <option name="test-file-name" value="BinderProxyCountingTestService.apk" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
diff --git a/core/tests/coretests/BinderProxyCountingTestApp/AndroidManifest.xml b/core/tests/coretests/BinderProxyCountingTestApp/AndroidManifest.xml
index a971730..c8407b8 100644
--- a/core/tests/coretests/BinderProxyCountingTestApp/AndroidManifest.xml
+++ b/core/tests/coretests/BinderProxyCountingTestApp/AndroidManifest.xml
@@ -16,6 +16,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.frameworks.coretests.binderproxycountingtestapp">
+ <queries>
+ <package android:name="com.android.frameworks.coretests.binderproxycountingtestservice" />
+ </queries>
<application>
<service android:name=".BpcTestAppCmdService"
android:exported="true"/>
diff --git a/core/tests/coretests/BinderProxyCountingTestApp/src/com/android/frameworks/coretests/binderproxycountingtestapp/BpcTestAppCmdService.java b/core/tests/coretests/BinderProxyCountingTestApp/src/com/android/frameworks/coretests/binderproxycountingtestapp/BpcTestAppCmdService.java
index 5aae1203..a7e97d3 100644
--- a/core/tests/coretests/BinderProxyCountingTestApp/src/com/android/frameworks/coretests/binderproxycountingtestapp/BpcTestAppCmdService.java
+++ b/core/tests/coretests/BinderProxyCountingTestApp/src/com/android/frameworks/coretests/binderproxycountingtestapp/BpcTestAppCmdService.java
@@ -17,14 +17,15 @@
package com.android.frameworks.coretests.binderproxycountingtestapp;
import android.app.Service;
-import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.ServiceConnection;
+import android.database.ContentObserver;
+import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
+import android.provider.Settings;
import android.util.Log;
import com.android.frameworks.coretests.aidl.IBinderProxyCountingService;
@@ -49,24 +50,20 @@
private IBpcTestAppCmdService.Stub mBinder = new IBpcTestAppCmdService.Stub() {
- private ArrayList<BroadcastReceiver> mBrList = new ArrayList();
+ private ArrayList<ContentObserver> mCoList = new ArrayList();
private ArrayList<ITestRemoteCallback> mTrcList = new ArrayList();
+ private Handler mHandler = new Handler();
@Override
public void createSystemBinders(int count) {
int i = 0;
while (i++ < count) {
- BroadcastReceiver br = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
-
- }
- };
- IntentFilter filt = new IntentFilter(Intent.ACTION_POWER_DISCONNECTED);
- synchronized (mBrList) {
- mBrList.add(br);
+ final ContentObserver co = new ContentObserver(mHandler) {};
+ synchronized (mCoList) {
+ mCoList.add(co);
}
- registerReceiver(br, filt);
+ getContentResolver().registerContentObserver(
+ Settings.System.CONTENT_URI, false, co);
}
}
@@ -74,11 +71,11 @@
public void releaseSystemBinders(int count) {
int i = 0;
while (i++ < count) {
- BroadcastReceiver br;
- synchronized (mBrList) {
- br = mBrList.remove(0);
+ ContentObserver co;
+ synchronized (mCoList) {
+ co = mCoList.remove(0);
}
- unregisterReceiver(br);
+ getContentResolver().unregisterContentObserver(co);
}
}
@@ -117,9 +114,9 @@
@Override
public void releaseAllBinders() {
- synchronized (mBrList) {
- while (mBrList.size() > 0) {
- unregisterReceiver(mBrList.remove(0));
+ synchronized (mCoList) {
+ while (mCoList.size() > 0) {
+ getContentResolver().unregisterContentObserver(mCoList.remove(0));
}
}
synchronized (mTrcList) {
@@ -179,4 +176,4 @@
public IBinder onBind(Intent intent) {
return mBinder;
}
-}
\ No newline at end of file
+}
diff --git a/core/tests/coretests/BinderProxyCountingTestService/src/com/android/frameworks/coretests/binderproxycountingtestservice/BpcTestServiceCmdService.java b/core/tests/coretests/BinderProxyCountingTestService/src/com/android/frameworks/coretests/binderproxycountingtestservice/BpcTestServiceCmdService.java
index 6bed2a2..0f1accc 100644
--- a/core/tests/coretests/BinderProxyCountingTestService/src/com/android/frameworks/coretests/binderproxycountingtestservice/BpcTestServiceCmdService.java
+++ b/core/tests/coretests/BinderProxyCountingTestService/src/com/android/frameworks/coretests/binderproxycountingtestservice/BpcTestServiceCmdService.java
@@ -55,8 +55,8 @@
}
@Override
- public void setBinderProxyWatermarks(int high, int low) {
- BinderInternal.nSetBinderProxyCountWatermarks(high, low);
+ public void setBinderProxyWatermarks(int high, int low, int warning) {
+ BinderInternal.nSetBinderProxyCountWatermarks(high, low, warning);
}
@Override
@@ -68,12 +68,23 @@
public void setBinderProxyCountCallback(IBpcCallbackObserver observer) {
if (observer != null) {
BinderInternal.setBinderProxyCountCallback(
- new BinderInternal.BinderProxyLimitListener() {
+ new BinderInternal.BinderProxyCountEventListener() {
@Override
public void onLimitReached(int uid) {
try {
synchronized (observer) {
- observer.onCallback(uid);
+ observer.onLimitReached(uid);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, e.toString());
+ }
+ }
+
+ @Override
+ public void onWarningThresholdReached(int uid) {
+ try {
+ synchronized (observer) {
+ observer.onWarningThresholdReached(uid);
}
} catch (Exception e) {
Log.e(TAG, e.toString());
@@ -98,4 +109,4 @@
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
}
-}
\ No newline at end of file
+}
diff --git a/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcCallbackObserver.aidl b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcCallbackObserver.aidl
index c4ebd56..ada7d92 100644
--- a/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcCallbackObserver.aidl
+++ b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcCallbackObserver.aidl
@@ -17,5 +17,6 @@
package com.android.frameworks.coretests.aidl;
interface IBpcCallbackObserver {
- void onCallback(int uid);
-}
\ No newline at end of file
+ void onLimitReached(int uid);
+ void onWarningThresholdReached(int uid);
+}
diff --git a/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcTestServiceCmdService.aidl b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcTestServiceCmdService.aidl
index abdab41..cdcda9d 100644
--- a/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcTestServiceCmdService.aidl
+++ b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcTestServiceCmdService.aidl
@@ -20,7 +20,7 @@
interface IBpcTestServiceCmdService {
void forceGc();
int getBinderProxyCount(int uid);
- void setBinderProxyWatermarks(int high, int low);
+ void setBinderProxyWatermarks(int high, int low, int warning);
void enableBinderProxyLimit(boolean enable);
void setBinderProxyCountCallback(IBpcCallbackObserver observer);
-}
\ No newline at end of file
+}
diff --git a/core/tests/coretests/src/android/os/BinderProxyCountingTest.java b/core/tests/coretests/src/android/os/BinderProxyCountingTest.java
index bcd9521..84d2995 100644
--- a/core/tests/coretests/src/android/os/BinderProxyCountingTest.java
+++ b/core/tests/coretests/src/android/os/BinderProxyCountingTest.java
@@ -88,9 +88,10 @@
private static final int BIND_SERVICE_TIMEOUT_SEC = 5;
private static final int TOO_MANY_BINDERS_TIMEOUT_SEC = 2;
+ private static final int TOO_MANY_BINDERS_WITH_KILL_TIMEOUT_SEC = 30;
- // Keep in sync with sBinderProxyCountLimit in BpBinder.cpp
- private static final int BINDER_PROXY_LIMIT = 2500;
+ // Keep in sync with BINDER_PROXY_HIGH_WATERMARK in ActivityManagerService.java
+ private static final int BINDER_PROXY_LIMIT = 6000;
private static Context sContext;
private static UiDevice sUiDevice;
@@ -175,18 +176,26 @@
}
}
- private CountDownLatch createBinderLimitLatch() throws RemoteException {
- final CountDownLatch latch = new CountDownLatch(1);
+ private CountDownLatch[] createBinderLimitLatch() throws RemoteException {
+ final CountDownLatch[] latches = new CountDownLatch[] {
+ new CountDownLatch(1), new CountDownLatch(1)
+ };
sBpcTestServiceCmdService.setBinderProxyCountCallback(
new IBpcCallbackObserver.Stub() {
@Override
- public void onCallback(int uid) {
+ public void onLimitReached(int uid) {
if (uid == sTestPkgUid) {
- latch.countDown();
+ latches[0].countDown();
+ }
+ }
+ @Override
+ public void onWarningThresholdReached(int uid) {
+ if (uid == sTestPkgUid) {
+ latches[1].countDown();
}
}
});
- return latch;
+ return latches;
}
/**
@@ -227,6 +236,7 @@
@Test
public void testBinderProxyLimitBoundary() throws Exception {
final int binderProxyLimit = 2000;
+ final int binderProxyWarning = 1900;
final int rearmThreshold = 1800;
try {
sTestAppConnection = bindService(sTestAppConsumer, sTestAppIntent);
@@ -238,19 +248,33 @@
// Get the baseline of binders naturally held by the test Package
int baseBinderCount = sBpcTestServiceCmdService.getBinderProxyCount(sTestPkgUid);
- final CountDownLatch binderLimitLatch = createBinderLimitLatch();
- sBpcTestServiceCmdService.setBinderProxyWatermarks(binderProxyLimit, rearmThreshold);
+ final CountDownLatch[] binderLatches = createBinderLimitLatch();
+ sBpcTestServiceCmdService.setBinderProxyWatermarks(binderProxyLimit, rearmThreshold,
+ binderProxyWarning);
+
+ // Create Binder Proxies up to the warning;
+ sBpcTestAppCmdService.createTestBinders(binderProxyWarning - baseBinderCount);
+ if (binderLatches[1].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ fail("Received BinderProxyLimitCallback for uid " + sTestPkgUid
+ + " when proxy warning should not have been triggered");
+ }
+
+ // Create one more Binder to trigger the warning
+ sBpcTestAppCmdService.createTestBinders(1);
+ if (!binderLatches[1].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ fail("Timed out waiting for uid " + sTestPkgUid + " to trigger the warning");
+ }
// Create Binder Proxies up to the limit
- sBpcTestAppCmdService.createTestBinders(binderProxyLimit - baseBinderCount);
- if (binderLimitLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ sBpcTestAppCmdService.createTestBinders(binderProxyLimit - binderProxyWarning - 1);
+ if (binderLatches[0].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
fail("Received BinderProxyLimitCallback for uid " + sTestPkgUid
+ " when proxy limit should not have been reached");
}
// Create one more Binder to cross the limit
sBpcTestAppCmdService.createTestBinders(1);
- if (!binderLimitLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ if (!binderLatches[0].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
fail("Timed out waiting for uid " + sTestPkgUid + " to hit limit");
}
@@ -274,12 +298,20 @@
sBpcTestServiceCmdService.forceGc();
int baseBinderCount = sBpcTestServiceCmdService.getBinderProxyCount(sTestPkgUid);
for (int testLimit : testLimits) {
- final CountDownLatch binderLimitLatch = createBinderLimitLatch();
+ final CountDownLatch[] binderLatches = createBinderLimitLatch();
// Change the BinderProxyLimit
- sBpcTestServiceCmdService.setBinderProxyWatermarks(testLimit, baseBinderCount + 10);
+ sBpcTestServiceCmdService.setBinderProxyWatermarks(testLimit, baseBinderCount + 10,
+ testLimit - 10);
+
+ // Trigger the new Binder Proxy warning
+ sBpcTestAppCmdService.createTestBinders(testLimit - 9 - baseBinderCount);
+ if (!binderLatches[1].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ fail("Timed out waiting for uid " + sTestPkgUid + " to trigger the warning");
+ }
+
// Exceed the new Binder Proxy Limit
- sBpcTestAppCmdService.createTestBinders(testLimit + 1);
- if (!binderLimitLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ sBpcTestAppCmdService.createTestBinders(10);
+ if (!binderLatches[0].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
fail("Timed out waiting for uid " + sTestPkgUid + " to hit limit");
}
@@ -297,6 +329,7 @@
public void testRearmCallbackThreshold() throws Exception {
final int binderProxyLimit = 2000;
final int exceedBinderProxyLimit = binderProxyLimit + 10;
+ final int binderProxyWarning = 1900;
final int rearmThreshold = 1800;
try {
sTestAppConnection = bindService(sTestAppConsumer, sTestAppIntent);
@@ -305,11 +338,19 @@
sBpcTestServiceCmdService.enableBinderProxyLimit(true);
sBpcTestServiceCmdService.forceGc();
- final CountDownLatch firstBinderLimitLatch = createBinderLimitLatch();
- sBpcTestServiceCmdService.setBinderProxyWatermarks(binderProxyLimit, rearmThreshold);
+ int baseBinderCount = sBpcTestServiceCmdService.getBinderProxyCount(sTestPkgUid);
+ final CountDownLatch[] firstBinderLatches = createBinderLimitLatch();
+ sBpcTestServiceCmdService.setBinderProxyWatermarks(binderProxyLimit, rearmThreshold,
+ binderProxyWarning);
+ // Trigger the Binder Proxy Waring
+ sBpcTestAppCmdService.createTestBinders(binderProxyWarning - baseBinderCount + 1);
+ if (!firstBinderLatches[1].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ fail("Timed out waiting for uid " + sTestPkgUid + " to trigger warning");
+ }
+
// Exceed the Binder Proxy Limit
- sBpcTestAppCmdService.createTestBinders(exceedBinderProxyLimit);
- if (!firstBinderLimitLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ sBpcTestAppCmdService.createTestBinders(exceedBinderProxyLimit - binderProxyWarning);
+ if (!firstBinderLatches[0].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
fail("Timed out waiting for uid " + sTestPkgUid + " to hit limit");
}
@@ -321,11 +362,20 @@
sBpcTestServiceCmdService.forceGc();
currentBinderCount = sBpcTestServiceCmdService.getBinderProxyCount(sTestPkgUid);
- final CountDownLatch secondBinderLimitLatch = createBinderLimitLatch();
+ final CountDownLatch[] secondBinderLatches = createBinderLimitLatch();
+
+ // Exceed the Binder Proxy warning which should not cause a callback since there has
+ // been no rearm
+ sBpcTestAppCmdService.createTestBinders(binderProxyWarning - currentBinderCount + 1);
+ if (secondBinderLatches[1].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ fail("Received BinderProxyLimitCallback for uid " + sTestPkgUid
+ + " when the callback has not been rearmed yet");
+ }
+
// Exceed the Binder Proxy limit which should not cause a callback since there has
// been no rearm
- sBpcTestAppCmdService.createTestBinders(exceedBinderProxyLimit - currentBinderCount);
- if (secondBinderLimitLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ sBpcTestAppCmdService.createTestBinders(exceedBinderProxyLimit - binderProxyWarning);
+ if (secondBinderLatches[0].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
fail("Received BinderProxyLimitCallback for uid " + sTestPkgUid
+ " when the callback has not been rearmed yet");
}
@@ -337,10 +387,16 @@
sBpcTestServiceCmdService.forceGc();
currentBinderCount = sBpcTestServiceCmdService.getBinderProxyCount(sTestPkgUid);
+ // Trigger the Binder Proxy Waring
+ sBpcTestAppCmdService.createTestBinders(binderProxyWarning - currentBinderCount + 1);
+ if (!secondBinderLatches[1].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ fail("Timed out waiting for uid " + sTestPkgUid + " to trigger warning");
+ }
+
// Exceed the Binder Proxy limit for the last time
sBpcTestAppCmdService.createTestBinders(exceedBinderProxyLimit - currentBinderCount);
- if (!secondBinderLimitLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ if (!secondBinderLatches[0].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
fail("Timed out waiting for uid " + sTestPkgUid + " to hit limit");
}
sBpcTestAppCmdService.releaseTestBinders(currentBinderCount);
@@ -373,7 +429,7 @@
// is not unexpected
}
- if (!binderDeathLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ if (!binderDeathLatch.await(TOO_MANY_BINDERS_WITH_KILL_TIMEOUT_SEC, TimeUnit.SECONDS)) {
sBpcTestAppCmdService.releaseSystemBinders(exceedBinderProxyLimit);
fail("Timed out waiting for uid " + sTestPkgUid + " to die.");
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIService.java b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
index 76c2282..d596288 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIService.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
@@ -99,9 +99,10 @@
if (Build.IS_DEBUGGABLE) {
// b/71353150 - looking for leaked binder proxies
BinderInternal.nSetBinderProxyCountEnabled(true);
- BinderInternal.nSetBinderProxyCountWatermarks(1000,900);
+ BinderInternal.nSetBinderProxyCountWatermarks(
+ /* high= */ 1000, /* low= */ 900, /* warning= */ 950);
BinderInternal.setBinderProxyCountCallback(
- new BinderInternal.BinderProxyLimitListener() {
+ new BinderInternal.BinderProxyCountEventListener() {
@Override
public void onLimitReached(int uid) {
Slog.w(SystemUIApplication.TAG,
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 0711b71..d35892e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -413,6 +413,7 @@
import com.android.internal.os.BinderCallHeavyHitterWatcher.BinderCallHeavyHitterListener;
import com.android.internal.os.BinderCallHeavyHitterWatcher.HeavyHitterContainer;
import com.android.internal.os.BinderInternal;
+import com.android.internal.os.BinderInternal.BinderProxyCountEventListener;
import com.android.internal.os.BinderTransactionNameResolver;
import com.android.internal.os.ByteTransferPipe;
import com.android.internal.os.IResultReceiver;
@@ -610,8 +611,8 @@
private static final int MINIMUM_MEMORY_GROWTH_THRESHOLD = 10 * 1000; // 10 MB
/**
- * The number of binder proxies we need to have before we start warning and
- * dumping debug info.
+ * The number of binder proxies we need to have before we start dumping debug info
+ * and kill the offenders.
*/
private static final int BINDER_PROXY_HIGH_WATERMARK = 6000;
@@ -621,6 +622,11 @@
*/
private static final int BINDER_PROXY_LOW_WATERMARK = 5500;
+ /**
+ * The number of binder proxies we need to have before we start warning.
+ */
+ private static final int BINDER_PROXY_WARNING_WATERMARK = 5750;
+
// Max character limit for a notification title. If the notification title is larger than this
// the notification will not be legible to the user.
private static final int MAX_BUGREPORT_TITLE_SIZE = 100;
@@ -8926,33 +8932,10 @@
t.traceBegin("setBinderProxies");
BinderInternal.nSetBinderProxyCountWatermarks(BINDER_PROXY_HIGH_WATERMARK,
- BINDER_PROXY_LOW_WATERMARK);
+ BINDER_PROXY_LOW_WATERMARK, BINDER_PROXY_WARNING_WATERMARK);
BinderInternal.nSetBinderProxyCountEnabled(true);
- BinderInternal.setBinderProxyCountCallback(
- (uid) -> {
- Slog.wtf(TAG, "Uid " + uid + " sent too many Binders to uid "
- + Process.myUid());
- BinderProxy.dumpProxyDebugInfo();
- if (uid == Process.SYSTEM_UID) {
- Slog.i(TAG, "Skipping kill (uid is SYSTEM)");
- } else {
- killUid(UserHandle.getAppId(uid), UserHandle.getUserId(uid),
- ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE,
- ApplicationExitInfo.SUBREASON_EXCESSIVE_BINDER_OBJECTS,
- "Too many Binders sent to SYSTEM");
- // We need to run a GC here, because killing the processes involved
- // actually isn't guaranteed to free up the proxies; in fact, if the
- // GC doesn't run for a long time, we may even exceed the global
- // proxy limit for a process (20000), resulting in system_server itself
- // being killed.
- // Note that the GC here might not actually clean up all the proxies,
- // because the binder reference decrements will come in asynchronously;
- // but if new processes belonging to the UID keep adding proxies, we
- // will get another callback here, and run the GC again - this time
- // cleaning up the old proxies.
- VMRuntime.getRuntime().requestConcurrentGC();
- }
- }, BackgroundThread.getHandler());
+ BinderInternal.setBinderProxyCountCallback(new MyBinderProxyCountEventListener(),
+ BackgroundThread.getHandler());
t.traceEnd(); // setBinderProxies
t.traceEnd(); // ActivityManagerStartApps
@@ -8967,6 +8950,45 @@
}
}
+ private class MyBinderProxyCountEventListener implements BinderProxyCountEventListener {
+ @Override
+ public void onLimitReached(int uid) {
+ Slog.wtf(TAG, "Uid " + uid + " sent too many Binders to uid "
+ + Process.myUid());
+ BinderProxy.dumpProxyDebugInfo();
+ if (uid == Process.SYSTEM_UID) {
+ Slog.i(TAG, "Skipping kill (uid is SYSTEM)");
+ } else {
+ killUid(UserHandle.getAppId(uid), UserHandle.getUserId(uid),
+ ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE,
+ ApplicationExitInfo.SUBREASON_EXCESSIVE_BINDER_OBJECTS,
+ "Too many Binders sent to SYSTEM");
+ // We need to run a GC here, because killing the processes involved
+ // actually isn't guaranteed to free up the proxies; in fact, if the
+ // GC doesn't run for a long time, we may even exceed the global
+ // proxy limit for a process (20000), resulting in system_server itself
+ // being killed.
+ // Note that the GC here might not actually clean up all the proxies,
+ // because the binder reference decrements will come in asynchronously;
+ // but if new processes belonging to the UID keep adding proxies, we
+ // will get another callback here, and run the GC again - this time
+ // cleaning up the old proxies.
+ VMRuntime.getRuntime().requestConcurrentGC();
+ }
+ }
+
+ @Override
+ public void onWarningThresholdReached(int uid) {
+ if (com.android.server.am.Flags.logExcessiveBinderProxies()) {
+ Slog.w(TAG, "Uid " + uid + " sent too many ("
+ + BINDER_PROXY_WARNING_WATERMARK + ") Binders to uid " + Process.myUid());
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.EXCESSIVE_BINDER_PROXY_COUNT_REPORTED,
+ uid);
+ }
+ }
+ }
+
private void watchDeviceProvisioning(Context context) {
// setting system property based on whether device is provisioned