Merge "Java side setup and access to Binder Proxy Tracking"
This commit is contained in:
@@ -16,9 +16,15 @@
|
||||
|
||||
package com.android.internal.os;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.SystemClock;
|
||||
import android.util.EventLog;
|
||||
import android.util.Log;
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import dalvik.system.VMRuntime;
|
||||
|
||||
@@ -31,11 +37,14 @@ import java.util.ArrayList;
|
||||
* @see IBinder
|
||||
*/
|
||||
public class BinderInternal {
|
||||
private static final String TAG = "BinderInternal";
|
||||
static WeakReference<GcWatcher> sGcWatcher
|
||||
= new WeakReference<GcWatcher>(new GcWatcher());
|
||||
static ArrayList<Runnable> sGcWatchers = new ArrayList<>();
|
||||
static Runnable[] sTmpWatchers = new Runnable[1];
|
||||
static long sLastGcTime;
|
||||
static final BinderProxyLimitListenerDelegate sBinderProxyLimitListenerDelegate =
|
||||
new BinderProxyLimitListenerDelegate();
|
||||
|
||||
static final class GcWatcher {
|
||||
@Override
|
||||
@@ -106,4 +115,96 @@ public class BinderInternal {
|
||||
static void forceBinderGc() {
|
||||
forceGc("Binder");
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable Binder Proxy Instance Counting by Uid. While enabled, the set callback will
|
||||
* be called if this process holds too many Binder Proxies on behalf of a Uid.
|
||||
* @param enabled true to enable counting, false to disable
|
||||
*/
|
||||
public static final native void nSetBinderProxyCountEnabled(boolean enabled);
|
||||
|
||||
/**
|
||||
* Get the current number of Binder Proxies held for each uid.
|
||||
* @return SparseIntArray mapping uids to the number of Binder Proxies currently held
|
||||
*/
|
||||
public static final native SparseIntArray nGetBinderProxyPerUidCounts();
|
||||
|
||||
/**
|
||||
* Get the current number of Binder Proxies held for an individual uid.
|
||||
* @param uid Requested uid for Binder Proxy count
|
||||
* @return int with the number of Binder proxies held for a uid
|
||||
*/
|
||||
public static final native int nGetBinderProxyCount(int uid);
|
||||
|
||||
/**
|
||||
* Set the Binder Proxy watermarks. Default high watermark = 2500. Default low watermark = 2000
|
||||
* @param high The limit at which the BinderProxyListener callback will be called.
|
||||
* @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)
|
||||
*/
|
||||
public static final native void nSetBinderProxyCountWatermarks(int high, int low);
|
||||
|
||||
/**
|
||||
* 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 void onLimitReached(int 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 allowed limit.
|
||||
* @param uid The uid of the bad behaving app sending too many binders
|
||||
*/
|
||||
public static void binderProxyLimitCallbackFromNative(int uid) {
|
||||
sBinderProxyLimitListenerDelegate.notifyClient(uid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a callback to be triggered when a uid's Binder Proxy limit is reached for this process.
|
||||
* @param listener OnLimitReached of listener will be called in the thread provided by handler
|
||||
* @param handler must not be null, callback will be posted through the handler;
|
||||
*
|
||||
*/
|
||||
public static void setBinderProxyCountCallback(BinderProxyLimitListener listener,
|
||||
@NonNull Handler handler) {
|
||||
Preconditions.checkNotNull(handler,
|
||||
"Must provide NonNull Handler to setBinderProxyCountCallback when setting "
|
||||
+ "BinderProxyLimitListener");
|
||||
sBinderProxyLimitListenerDelegate.setListener(listener, handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the Binder Proxy callback
|
||||
*/
|
||||
public static void clearBinderProxyCountCallback() {
|
||||
sBinderProxyLimitListenerDelegate.setListener(null, null);
|
||||
}
|
||||
|
||||
static private class BinderProxyLimitListenerDelegate {
|
||||
private BinderProxyLimitListener mBinderProxyLimitListener;
|
||||
private Handler mHandler;
|
||||
|
||||
void setListener(BinderProxyLimitListener listener, Handler handler) {
|
||||
synchronized (this) {
|
||||
mBinderProxyLimitListener = listener;
|
||||
mHandler = handler;
|
||||
}
|
||||
}
|
||||
|
||||
void notifyClient(final int uid) {
|
||||
synchronized (this) {
|
||||
if (mBinderProxyLimitListener != null) {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mBinderProxyLimitListener.onLimitReached(uid);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <binder/IServiceManager.h>
|
||||
#include <binder/IPCThreadState.h>
|
||||
#include <binder/Parcel.h>
|
||||
#include <binder/BpBinder.h>
|
||||
#include <binder/ProcessState.h>
|
||||
#include <cutils/atomic.h>
|
||||
#include <log/log.h>
|
||||
@@ -81,9 +82,17 @@ static struct binderinternal_offsets_t
|
||||
// Class state.
|
||||
jclass mClass;
|
||||
jmethodID mForceGc;
|
||||
jmethodID mProxyLimitCallback;
|
||||
|
||||
} gBinderInternalOffsets;
|
||||
|
||||
static struct sparseintarray_offsets_t
|
||||
{
|
||||
jclass classObject;
|
||||
jmethodID constructor;
|
||||
jmethodID put;
|
||||
} gSparseIntArrayOffsets;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static struct error_offsets_t
|
||||
@@ -993,6 +1002,43 @@ static void android_os_BinderInternal_handleGc(JNIEnv* env, jobject clazz)
|
||||
gCollectedAtRefs = gNumLocalRefsCreated + gNumDeathRefsCreated;
|
||||
}
|
||||
|
||||
static void android_os_BinderInternal_proxyLimitcallback(int uid)
|
||||
{
|
||||
JNIEnv *env = AndroidRuntime::getJNIEnv();
|
||||
env->CallStaticVoidMethod(gBinderInternalOffsets.mClass,
|
||||
gBinderInternalOffsets.mProxyLimitCallback,
|
||||
uid);
|
||||
}
|
||||
|
||||
static void android_os_BinderInternal_setBinderProxyCountEnabled(JNIEnv* env, jobject clazz,
|
||||
jboolean enable)
|
||||
{
|
||||
BpBinder::setCountByUidEnabled((bool) enable);
|
||||
}
|
||||
|
||||
static jobject android_os_BinderInternal_getBinderProxyPerUidCounts(JNIEnv* env, jclass clazz)
|
||||
{
|
||||
Vector<uint32_t> uids, counts;
|
||||
BpBinder::getCountByUid(uids, counts);
|
||||
jobject sparseIntArray = env->NewObject(gSparseIntArrayOffsets.classObject,
|
||||
gSparseIntArrayOffsets.constructor);
|
||||
for (size_t i = 0; i < uids.size(); i++) {
|
||||
env->CallVoidMethod(sparseIntArray, gSparseIntArrayOffsets.put,
|
||||
static_cast<jint>(uids[i]), static_cast<jint>(counts[i]));
|
||||
}
|
||||
return sparseIntArray;
|
||||
}
|
||||
|
||||
static jint android_os_BinderInternal_getBinderProxyCount(JNIEnv* env, jobject clazz, jint uid) {
|
||||
return static_cast<jint>(BpBinder::getBinderProxyCount(static_cast<uint32_t>(uid)));
|
||||
}
|
||||
|
||||
static void android_os_BinderInternal_setBinderProxyCountWatermarks(JNIEnv* env, jobject clazz,
|
||||
jint high, jint low)
|
||||
{
|
||||
BpBinder::setBinderProxyCountWatermarks(high, low);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static const JNINativeMethod gBinderInternalMethods[] = {
|
||||
@@ -1001,7 +1047,11 @@ static const JNINativeMethod gBinderInternalMethods[] = {
|
||||
{ "joinThreadPool", "()V", (void*)android_os_BinderInternal_joinThreadPool },
|
||||
{ "disableBackgroundScheduling", "(Z)V", (void*)android_os_BinderInternal_disableBackgroundScheduling },
|
||||
{ "setMaxThreads", "(I)V", (void*)android_os_BinderInternal_setMaxThreads },
|
||||
{ "handleGc", "()V", (void*)android_os_BinderInternal_handleGc }
|
||||
{ "handleGc", "()V", (void*)android_os_BinderInternal_handleGc },
|
||||
{ "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}
|
||||
};
|
||||
|
||||
const char* const kBinderInternalPathName = "com/android/internal/os/BinderInternal";
|
||||
@@ -1012,6 +1062,16 @@ static int int_register_android_os_BinderInternal(JNIEnv* env)
|
||||
|
||||
gBinderInternalOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
|
||||
gBinderInternalOffsets.mForceGc = GetStaticMethodIDOrDie(env, clazz, "forceBinderGc", "()V");
|
||||
gBinderInternalOffsets.mProxyLimitCallback = GetStaticMethodIDOrDie(env, clazz, "binderProxyLimitCallbackFromNative", "(I)V");
|
||||
|
||||
jclass SparseIntArrayClass = FindClassOrDie(env, "android/util/SparseIntArray");
|
||||
gSparseIntArrayOffsets.classObject = MakeGlobalRefOrDie(env, SparseIntArrayClass);
|
||||
gSparseIntArrayOffsets.constructor = GetMethodIDOrDie(env, gSparseIntArrayOffsets.classObject,
|
||||
"<init>", "()V");
|
||||
gSparseIntArrayOffsets.put = GetMethodIDOrDie(env, gSparseIntArrayOffsets.classObject, "put",
|
||||
"(II)V");
|
||||
|
||||
BpBinder::setLimitCallback(android_os_BinderInternal_proxyLimitcallback);
|
||||
|
||||
return RegisterMethodsOrDie(
|
||||
env, kBinderInternalPathName,
|
||||
|
||||
@@ -19,7 +19,12 @@ LOCAL_SRC_FILES := \
|
||||
$(call all-java-files-under, src) \
|
||||
$(call all-Iaidl-files-under, src) \
|
||||
$(call all-java-files-under, DisabledTestApp/src) \
|
||||
$(call all-java-files-under, EnabledTestApp/src)
|
||||
$(call all-java-files-under, EnabledTestApp/src) \
|
||||
$(call all-java-files-under, BinderProxyCountingTestApp/src) \
|
||||
$(call all-java-files-under, BinderProxyCountingTestService/src) \
|
||||
$(call all-Iaidl-files-under, aidl)
|
||||
|
||||
LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/aidl
|
||||
|
||||
LOCAL_DX_FLAGS := --core-library
|
||||
LOCAL_JACK_FLAGS := --multi-dex native
|
||||
|
||||
@@ -86,6 +86,7 @@
|
||||
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
|
||||
|
||||
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
|
||||
<uses-permission android:name="android.permission.KILL_UID" />
|
||||
|
||||
<!-- location test permissions -->
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
||||
|
||||
28
core/tests/coretests/BinderProxyCountingTestApp/Android.mk
Normal file
28
core/tests/coretests/BinderProxyCountingTestApp/Android.mk
Normal file
@@ -0,0 +1,28 @@
|
||||
# Copyright (C) 2017 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE_TAGS := tests
|
||||
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := coretests-aidl
|
||||
LOCAL_SRC_FILES := $(call all-subdir-java-files)
|
||||
|
||||
LOCAL_PACKAGE_NAME := BinderProxyCountingTestApp
|
||||
LOCAL_SDK_VERSION := current
|
||||
LOCAL_CERTIFICATE := platform
|
||||
|
||||
include $(BUILD_PACKAGE)
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2017 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.frameworks.coretests.binderproxycountingtestapp">
|
||||
|
||||
<application>
|
||||
<service android:name=".BpcTestAppCmdService"
|
||||
android:exported="true"/>
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
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.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.frameworks.coretests.aidl.IBinderProxyCountingService;
|
||||
import com.android.frameworks.coretests.aidl.IBpcTestAppCmdService;
|
||||
import com.android.frameworks.coretests.aidl.ITestRemoteCallback;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BpcTestAppCmdService extends Service {
|
||||
private static final String TAG = BpcTestAppCmdService.class.getSimpleName();
|
||||
|
||||
private static final String TEST_SERVICE_PKG =
|
||||
"com.android.frameworks.coretests.binderproxycountingtestservice";
|
||||
private static final String TEST_SERVICE_CLASS =
|
||||
TEST_SERVICE_PKG + ".BinderProxyCountingService";
|
||||
private static final int BIND_SERVICE_TIMEOUT_SEC = 5;
|
||||
|
||||
private static ServiceConnection mServiceConnection;
|
||||
private static IBinderProxyCountingService mBpcService;
|
||||
|
||||
private IBpcTestAppCmdService.Stub mBinder = new IBpcTestAppCmdService.Stub() {
|
||||
|
||||
private ArrayList<BroadcastReceiver> mBrList = new ArrayList();
|
||||
private ArrayList<ITestRemoteCallback> mTrcList = new ArrayList();
|
||||
|
||||
@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);
|
||||
}
|
||||
registerReceiver(br, filt);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseSystemBinders(int count) {
|
||||
int i = 0;
|
||||
while (i++ < count) {
|
||||
BroadcastReceiver br;
|
||||
synchronized (mBrList) {
|
||||
br = mBrList.remove(0);
|
||||
}
|
||||
unregisterReceiver(br);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createTestBinders(int count) {
|
||||
int i = 0;
|
||||
while (i++ < count) {
|
||||
ITestRemoteCallback cb = new ITestRemoteCallback.Stub() {};
|
||||
synchronized (mTrcList) {
|
||||
mTrcList.add(cb);
|
||||
}
|
||||
try {
|
||||
mBpcService.registerCallback(cb);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException caught! " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseTestBinders(int count) {
|
||||
int i = 0;
|
||||
while (i++ < count) {
|
||||
|
||||
ITestRemoteCallback cb;
|
||||
synchronized (mTrcList) {
|
||||
cb = mTrcList.remove(0);
|
||||
}
|
||||
try {
|
||||
mBpcService.unregisterCallback(cb);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException caught! " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseAllBinders() {
|
||||
synchronized (mBrList) {
|
||||
while (mBrList.size() > 0) {
|
||||
unregisterReceiver(mBrList.remove(0));
|
||||
}
|
||||
}
|
||||
synchronized (mTrcList) {
|
||||
while (mTrcList.size() > 0) {
|
||||
try {
|
||||
mBpcService.unregisterCallback(mTrcList.remove(0));
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException caught! " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String bindToTestService() {
|
||||
try {
|
||||
final CountDownLatch bindLatch = new CountDownLatch(1);
|
||||
mServiceConnection = new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
Log.i(TAG, "Service connected");
|
||||
mBpcService = IBinderProxyCountingService.Stub.asInterface(service);
|
||||
bindLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
Log.i(TAG, "Service disconnected");
|
||||
}
|
||||
};
|
||||
final Intent intent = new Intent()
|
||||
.setComponent(new ComponentName(TEST_SERVICE_PKG, TEST_SERVICE_CLASS));
|
||||
bindService(intent, mServiceConnection,
|
||||
Context.BIND_AUTO_CREATE
|
||||
| Context.BIND_ALLOW_OOM_MANAGEMENT
|
||||
| Context.BIND_NOT_FOREGROUND);
|
||||
if (!bindLatch.await(BIND_SERVICE_TIMEOUT_SEC, TimeUnit.SECONDS)) {
|
||||
throw new RuntimeException("Failed to bind to " + TEST_SERVICE_CLASS);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
unbindFromTestService();
|
||||
Log.e(TAG, e.toString());
|
||||
return e.toString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unbindFromTestService() {
|
||||
if (mBpcService != null) {
|
||||
unbindService(mServiceConnection);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return mBinder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
# Copyright (C) 2017 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE_TAGS := tests
|
||||
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := coretests-aidl
|
||||
LOCAL_SRC_FILES := $(call all-subdir-java-files)
|
||||
|
||||
LOCAL_PACKAGE_NAME := BinderProxyCountingTestService
|
||||
LOCAL_PRIVATE_PLATFORM_APIS := true
|
||||
LOCAL_CERTIFICATE := platform
|
||||
|
||||
include $(BUILD_PACKAGE)
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2017 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.frameworks.coretests.binderproxycountingtestservice">
|
||||
|
||||
<application>
|
||||
<service android:name=".BpcTestServiceCmdService"
|
||||
android:exported="true" />
|
||||
<service android:name=".BinderProxyCountingService"
|
||||
android:exported="true" />
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.frameworks.coretests.binderproxycountingtestservice;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteCallbackList;
|
||||
|
||||
import com.android.frameworks.coretests.aidl.IBinderProxyCountingService;
|
||||
import com.android.frameworks.coretests.aidl.ITestRemoteCallback;
|
||||
|
||||
public class BinderProxyCountingService extends Service {
|
||||
private static final String TAG = BinderProxyCountingService.class.getSimpleName();
|
||||
|
||||
private IBinderProxyCountingService.Stub mBinder = new IBinderProxyCountingService.Stub() {
|
||||
|
||||
final RemoteCallbackList<ITestRemoteCallback> mTestCallbacks = new RemoteCallbackList<>();
|
||||
|
||||
@Override
|
||||
public void registerCallback(ITestRemoteCallback callback) {
|
||||
synchronized (this) {
|
||||
mTestCallbacks.register(callback);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterCallback(ITestRemoteCallback callback) {
|
||||
synchronized (this) {
|
||||
mTestCallbacks.unregister(callback);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return mBinder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.frameworks.coretests.binderproxycountingtestservice;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.os.Debug;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.frameworks.coretests.aidl.IBpcCallbackObserver;
|
||||
import com.android.frameworks.coretests.aidl.IBpcTestServiceCmdService;
|
||||
import com.android.internal.os.BinderInternal;
|
||||
|
||||
public class BpcTestServiceCmdService extends Service {
|
||||
private static final String TAG = BpcTestServiceCmdService.class.getSimpleName();
|
||||
|
||||
//ServiceThread mHandlerThread;
|
||||
Handler mHandler;
|
||||
HandlerThread mHandlerThread;
|
||||
|
||||
private IBpcTestServiceCmdService.Stub mBinder = new IBpcTestServiceCmdService.Stub() {
|
||||
IBpcCallbackObserver mCallbackObserver;
|
||||
|
||||
@Override
|
||||
public void forceGc() {
|
||||
int gcCount = Integer.parseInt(Debug.getRuntimeStat("art.gc.gc-count"));
|
||||
int i = 20;
|
||||
while (gcCount == Integer.parseInt(Debug.getRuntimeStat("art.gc.gc-count")) && i > 0) {
|
||||
System.gc();
|
||||
System.runFinalization();
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBinderProxyCount(int uid) {
|
||||
return BinderInternal.nGetBinderProxyCount(uid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBinderProxyWatermarks(int high, int low) {
|
||||
BinderInternal.nSetBinderProxyCountWatermarks(high, low);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableBinderProxyLimit(boolean enable) {
|
||||
BinderInternal.nSetBinderProxyCountEnabled(enable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBinderProxyCountCallback(IBpcCallbackObserver observer) {
|
||||
if (observer != null) {
|
||||
BinderInternal.setBinderProxyCountCallback(
|
||||
new BinderInternal.BinderProxyLimitListener() {
|
||||
@Override
|
||||
public void onLimitReached(int uid) {
|
||||
try {
|
||||
synchronized (observer) {
|
||||
observer.onCallback(uid);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, e.toString());
|
||||
}
|
||||
}
|
||||
}, mHandler);
|
||||
} else {
|
||||
BinderInternal.clearBinderProxyCountCallback();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return mBinder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate()
|
||||
{
|
||||
mHandlerThread = new HandlerThread("BinderProxyCountingServiceThread");
|
||||
mHandlerThread.start();
|
||||
mHandler = new Handler(mHandlerThread.getLooper());
|
||||
}
|
||||
}
|
||||
22
core/tests/coretests/aidl/Android.mk
Normal file
22
core/tests/coretests/aidl/Android.mk
Normal file
@@ -0,0 +1,22 @@
|
||||
# Copyright (C) 2017 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE_TAGS := tests
|
||||
LOCAL_SDK_VERSION := current
|
||||
LOCAL_SRC_FILES := $(call all-subdir-Iaidl-files)
|
||||
LOCAL_MODULE := coretests-aidl
|
||||
include $(BUILD_STATIC_JAVA_LIBRARY)
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.frameworks.coretests.aidl;
|
||||
import com.android.frameworks.coretests.aidl.ITestRemoteCallback;
|
||||
|
||||
interface IBinderProxyCountingService {
|
||||
void registerCallback(in ITestRemoteCallback callback);
|
||||
void unregisterCallback(in ITestRemoteCallback callback);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.frameworks.coretests.aidl;
|
||||
|
||||
interface IBpcCallbackObserver {
|
||||
void onCallback(int uid);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.frameworks.coretests.aidl;
|
||||
|
||||
interface IBpcTestAppCmdService {
|
||||
void createSystemBinders(int count);
|
||||
void releaseSystemBinders(int count);
|
||||
|
||||
void createTestBinders(int count);
|
||||
void releaseTestBinders(int count);
|
||||
|
||||
void releaseAllBinders();
|
||||
|
||||
String bindToTestService();
|
||||
void unbindFromTestService();
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.frameworks.coretests.aidl;
|
||||
import com.android.frameworks.coretests.aidl.IBpcCallbackObserver;
|
||||
|
||||
interface IBpcTestServiceCmdService {
|
||||
void forceGc();
|
||||
int getBinderProxyCount(int uid);
|
||||
void setBinderProxyWatermarks(int high, int low);
|
||||
void enableBinderProxyLimit(boolean enable);
|
||||
void setBinderProxyCountCallback(IBpcCallbackObserver observer);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.frameworks.coretests.aidl;
|
||||
|
||||
interface ITestRemoteCallback {
|
||||
}
|
||||
378
core/tests/coretests/src/android/os/BinderProxyCountingTest.java
Normal file
378
core/tests/coretests/src/android/os/BinderProxyCountingTest.java
Normal file
@@ -0,0 +1,378 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.os;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.filters.LargeTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
import android.support.test.uiautomator.UiDevice;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.frameworks.coretests.aidl.IBpcCallbackObserver;
|
||||
import com.android.frameworks.coretests.aidl.IBpcTestAppCmdService;
|
||||
import com.android.frameworks.coretests.aidl.IBpcTestServiceCmdService;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Tests for verifying the Binder Proxy Counting and Limiting.
|
||||
*
|
||||
* To manually build and install relevant test apps
|
||||
*
|
||||
* Build:
|
||||
* mmma frameworks/base/core/tests/coretests/BinderProxyCountingTestApp
|
||||
* mmma frameworks/base/core/tests/coretests/BinderProxyCountingTestService
|
||||
* Install:
|
||||
* adb install -r \
|
||||
* ${ANDROID_PRODUCT_OUT}/data/app/BinderProxyCountingTestApp/BinderProxyCountingTestApp.apk
|
||||
* adb install -r \
|
||||
* ${ANDROID_PRODUCT_OUT}/data/app/BinderProxyCountingTestService/BinderProxyCountingTestService.apk
|
||||
*
|
||||
* To run the tests, use
|
||||
*
|
||||
* Build: m FrameworksCoreTests
|
||||
* Install: adb install -r \
|
||||
* ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
|
||||
* Run: adb shell am instrument -e class android.os.BinderProxyCountingTest -w \
|
||||
* com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
|
||||
*
|
||||
* or
|
||||
*
|
||||
* bit FrameworksCoreTests:android.os.BinderProxyCountingTest
|
||||
*/
|
||||
@LargeTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class BinderProxyCountingTest {
|
||||
private static final String TAG = BinderProxyCountingTest.class.getSimpleName();
|
||||
|
||||
private static final String TEST_APP_PKG =
|
||||
"com.android.frameworks.coretests.binderproxycountingtestapp";
|
||||
private static final String TEST_APP_CMD_SERVICE = TEST_APP_PKG + ".BpcTestAppCmdService";
|
||||
private static final String TEST_SERVICE_PKG =
|
||||
"com.android.frameworks.coretests.binderproxycountingtestservice";
|
||||
private static final String TEST_SERVICE_CMD_SERVICE =
|
||||
TEST_SERVICE_PKG + ".BpcTestServiceCmdService";
|
||||
|
||||
private static final int BIND_SERVICE_TIMEOUT_SEC = 5;
|
||||
private static final int TOO_MANY_BINDERS_TIMEOUT_SEC = 2;
|
||||
|
||||
// Keep in sync with sBinderProxyCountLimit in BpBinder.cpp
|
||||
private static final int BINDER_PROXY_LIMIT = 2500;
|
||||
|
||||
private static Context sContext;
|
||||
private static UiDevice sUiDevice;
|
||||
|
||||
private static ServiceConnection sTestAppConnection;
|
||||
private static ServiceConnection sTestServiceConnection;
|
||||
private static IBpcTestAppCmdService sBpcTestAppCmdService;
|
||||
private static IBpcTestServiceCmdService sBpcTestServiceCmdService;
|
||||
private static final Intent sTestAppIntent = new Intent()
|
||||
.setComponent(new ComponentName(TEST_APP_PKG, TEST_APP_CMD_SERVICE));
|
||||
private static final Intent sTestServiceIntent = new Intent()
|
||||
.setComponent(new ComponentName(TEST_SERVICE_PKG, TEST_SERVICE_CMD_SERVICE));
|
||||
private static final Consumer<IBinder> sTestAppConsumer = (service) -> {
|
||||
sBpcTestAppCmdService = IBpcTestAppCmdService.Stub.asInterface(service);
|
||||
};
|
||||
private static final Consumer<IBinder> sTestServiceConsumer = (service) -> {
|
||||
sBpcTestServiceCmdService = IBpcTestServiceCmdService.Stub.asInterface(service);
|
||||
};
|
||||
private static int sTestPkgUid;
|
||||
|
||||
/**
|
||||
* Setup any common data for the upcoming tests.
|
||||
*/
|
||||
@BeforeClass
|
||||
public static void setUpOnce() throws Exception {
|
||||
sContext = InstrumentationRegistry.getContext();
|
||||
sTestPkgUid = sContext.getPackageManager().getPackageUid(TEST_APP_PKG, 0);
|
||||
((ActivityManager) sContext.getSystemService(Context.ACTIVITY_SERVICE)).killUid(sTestPkgUid,
|
||||
"Wiping Test Package");
|
||||
|
||||
sUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
|
||||
}
|
||||
|
||||
private ServiceConnection bindService(final Consumer<IBinder> consumer, Intent intent)
|
||||
throws Exception {
|
||||
final CountDownLatch bindLatch = new CountDownLatch(1);
|
||||
ServiceConnection connection = new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
Log.i(TAG, "Service connected");
|
||||
consumer.accept(service);
|
||||
bindLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
Log.i(TAG, "Service disconnected");
|
||||
}
|
||||
};
|
||||
sContext.bindService(intent, connection,
|
||||
Context.BIND_AUTO_CREATE
|
||||
| Context.BIND_ALLOW_OOM_MANAGEMENT
|
||||
| Context.BIND_NOT_FOREGROUND);
|
||||
if (!bindLatch.await(BIND_SERVICE_TIMEOUT_SEC, TimeUnit.SECONDS)) {
|
||||
fail("Timed out waiting for the service to bind in " + sTestPkgUid);
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
|
||||
|
||||
private void unbindService(ServiceConnection service) {
|
||||
if (service != null) {
|
||||
sContext.unbindService(service);
|
||||
}
|
||||
}
|
||||
|
||||
private void bindTestAppToTestService() throws Exception {
|
||||
if (sBpcTestAppCmdService != null) {
|
||||
String errorMessage = sBpcTestAppCmdService.bindToTestService();
|
||||
if (errorMessage != null) {
|
||||
fail(errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void unbindTestAppFromTestService() throws Exception {
|
||||
if (sBpcTestAppCmdService != null) {
|
||||
sBpcTestAppCmdService.unbindFromTestService();
|
||||
}
|
||||
}
|
||||
|
||||
private CountDownLatch createBinderLimitLatch() throws RemoteException {
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
sBpcTestServiceCmdService.setBinderProxyCountCallback(
|
||||
new IBpcCallbackObserver.Stub() {
|
||||
@Override
|
||||
public void onCallback(int uid) {
|
||||
if (uid == sTestPkgUid) {
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
});
|
||||
return latch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Binder Proxy count held by SYSTEM for a given uid
|
||||
*/
|
||||
private int getSystemBinderCount(int uid) throws Exception {
|
||||
return Integer.parseInt(sUiDevice.executeShellCommand(
|
||||
"dumpsys activity binder-proxies " + uid).trim());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBinderProxyCount() throws Exception {
|
||||
// Arbitrary list of Binder create and release
|
||||
// Should cumulatively equal 0 and must never add up past the binder limit at any point
|
||||
int[] testValues = {223, -103, -13, 25, 90, -222};
|
||||
try {
|
||||
sTestAppConnection = bindService(sTestAppConsumer, sTestAppIntent);
|
||||
// Get the baseline of binders naturally held by the test Package
|
||||
int expectedBinderCount = getSystemBinderCount(sTestPkgUid);
|
||||
|
||||
for (int testValue : testValues) {
|
||||
if (testValue > 0) {
|
||||
sBpcTestAppCmdService.createSystemBinders(testValue);
|
||||
} else {
|
||||
sBpcTestAppCmdService.releaseSystemBinders(-testValue);
|
||||
}
|
||||
expectedBinderCount += testValue;
|
||||
int currentBinderCount = getSystemBinderCount(sTestPkgUid);
|
||||
assertEquals("Current Binder Count (" + currentBinderCount
|
||||
+ ") does not equal expected Binder Count (" + expectedBinderCount
|
||||
+ ")", expectedBinderCount, currentBinderCount);
|
||||
}
|
||||
} finally {
|
||||
unbindService(sTestAppConnection);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBinderProxyLimitBoundary() throws Exception {
|
||||
final int binderProxyLimit = 2000;
|
||||
final int rearmThreshold = 1800;
|
||||
try {
|
||||
sTestAppConnection = bindService(sTestAppConsumer, sTestAppIntent);
|
||||
sTestServiceConnection = bindService(sTestServiceConsumer, sTestServiceIntent);
|
||||
bindTestAppToTestService();
|
||||
sBpcTestServiceCmdService.enableBinderProxyLimit(true);
|
||||
|
||||
sBpcTestServiceCmdService.forceGc();
|
||||
// Get the baseline of binders naturally held by the test Package
|
||||
int baseBinderCount = sBpcTestServiceCmdService.getBinderProxyCount(sTestPkgUid);
|
||||
|
||||
final CountDownLatch binderLimitLatch = createBinderLimitLatch();
|
||||
sBpcTestServiceCmdService.setBinderProxyWatermarks(binderProxyLimit, rearmThreshold);
|
||||
|
||||
// Create Binder Proxies up to the limit
|
||||
sBpcTestAppCmdService.createTestBinders(binderProxyLimit - baseBinderCount);
|
||||
if (binderLimitLatch.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)) {
|
||||
fail("Timed out waiting for uid " + sTestPkgUid + " to hit limit");
|
||||
}
|
||||
|
||||
sBpcTestAppCmdService.releaseAllBinders();
|
||||
} finally {
|
||||
unbindTestAppFromTestService();
|
||||
unbindService(sTestAppConnection);
|
||||
unbindService(sTestServiceConnection);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetBinderProxyLimit() throws Exception {
|
||||
int[] testLimits = {1000, 222, 800};
|
||||
try {
|
||||
sTestAppConnection = bindService(sTestAppConsumer, sTestAppIntent);
|
||||
sTestServiceConnection = bindService(sTestServiceConsumer, sTestServiceIntent);
|
||||
bindTestAppToTestService();
|
||||
sBpcTestServiceCmdService.enableBinderProxyLimit(true);
|
||||
|
||||
sBpcTestServiceCmdService.forceGc();
|
||||
int baseBinderCount = sBpcTestServiceCmdService.getBinderProxyCount(sTestPkgUid);
|
||||
for (int testLimit : testLimits) {
|
||||
final CountDownLatch binderLimitLatch = createBinderLimitLatch();
|
||||
// Change the BinderProxyLimit
|
||||
sBpcTestServiceCmdService.setBinderProxyWatermarks(testLimit, baseBinderCount + 10);
|
||||
// Exceed the new Binder Proxy Limit
|
||||
sBpcTestAppCmdService.createTestBinders(testLimit + 1);
|
||||
if (!binderLimitLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
|
||||
fail("Timed out waiting for uid " + sTestPkgUid + " to hit limit");
|
||||
}
|
||||
|
||||
sBpcTestAppCmdService.releaseTestBinders(testLimit + 1);
|
||||
sBpcTestServiceCmdService.forceGc();
|
||||
}
|
||||
} finally {
|
||||
unbindTestAppFromTestService();
|
||||
unbindService(sTestAppConnection);
|
||||
unbindService(sTestServiceConnection);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRearmCallbackThreshold() throws Exception {
|
||||
final int binderProxyLimit = 2000;
|
||||
final int exceedBinderProxyLimit = binderProxyLimit + 10;
|
||||
final int rearmThreshold = 1800;
|
||||
try {
|
||||
sTestAppConnection = bindService(sTestAppConsumer, sTestAppIntent);
|
||||
sTestServiceConnection = bindService(sTestServiceConsumer, sTestServiceIntent);
|
||||
bindTestAppToTestService();
|
||||
sBpcTestServiceCmdService.enableBinderProxyLimit(true);
|
||||
|
||||
sBpcTestServiceCmdService.forceGc();
|
||||
final CountDownLatch firstBinderLimitLatch = createBinderLimitLatch();
|
||||
sBpcTestServiceCmdService.setBinderProxyWatermarks(binderProxyLimit, rearmThreshold);
|
||||
// Exceed the Binder Proxy Limit
|
||||
sBpcTestAppCmdService.createTestBinders(exceedBinderProxyLimit);
|
||||
if (!firstBinderLimitLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
|
||||
fail("Timed out waiting for uid " + sTestPkgUid + " to hit limit");
|
||||
}
|
||||
|
||||
sBpcTestServiceCmdService.forceGc();
|
||||
int currentBinderCount = sBpcTestServiceCmdService.getBinderProxyCount(sTestPkgUid);
|
||||
// Drop to the threshold, this should not rearm the callback
|
||||
sBpcTestAppCmdService.releaseTestBinders(currentBinderCount - rearmThreshold);
|
||||
|
||||
sBpcTestServiceCmdService.forceGc();
|
||||
currentBinderCount = sBpcTestServiceCmdService.getBinderProxyCount(sTestPkgUid);
|
||||
|
||||
final CountDownLatch secondBinderLimitLatch = createBinderLimitLatch();
|
||||
// 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)) {
|
||||
fail("Received BinderProxyLimitCallback for uid " + sTestPkgUid
|
||||
+ " when the callback has not been rearmed yet");
|
||||
}
|
||||
|
||||
sBpcTestServiceCmdService.forceGc();
|
||||
currentBinderCount = sBpcTestServiceCmdService.getBinderProxyCount(sTestPkgUid);
|
||||
// Drop below the rearmThreshold to rearm the BinderProxyLimitCallback
|
||||
sBpcTestAppCmdService.releaseTestBinders(currentBinderCount - rearmThreshold + 1);
|
||||
|
||||
sBpcTestServiceCmdService.forceGc();
|
||||
currentBinderCount = sBpcTestServiceCmdService.getBinderProxyCount(sTestPkgUid);
|
||||
// Exceed the Binder Proxy limit for the last time
|
||||
sBpcTestAppCmdService.createTestBinders(exceedBinderProxyLimit - currentBinderCount);
|
||||
|
||||
if (!secondBinderLimitLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
|
||||
fail("Timed out waiting for uid " + sTestPkgUid + " to hit limit");
|
||||
}
|
||||
sBpcTestAppCmdService.releaseTestBinders(currentBinderCount);
|
||||
} finally {
|
||||
unbindTestAppFromTestService();
|
||||
unbindService(sTestAppConnection);
|
||||
unbindService(sTestServiceConnection);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testKillBadBehavingApp() throws Exception {
|
||||
final CountDownLatch binderDeathLatch = new CountDownLatch(1);
|
||||
final int exceedBinderProxyLimit = BINDER_PROXY_LIMIT + 1;
|
||||
|
||||
try {
|
||||
sTestAppConnection = bindService(sTestAppConsumer, sTestAppIntent);
|
||||
sBpcTestAppCmdService.asBinder().linkToDeath(new IBinder.DeathRecipient() {
|
||||
@Override
|
||||
public void binderDied() {
|
||||
Log.v(TAG, "BpcTestAppCmdService died!");
|
||||
binderDeathLatch.countDown();
|
||||
}
|
||||
}, 0);
|
||||
try {
|
||||
// Exceed the Binder Proxy Limit emulating a bad behaving app
|
||||
sBpcTestAppCmdService.createSystemBinders(exceedBinderProxyLimit);
|
||||
} catch (DeadObjectException doe) {
|
||||
// We are expecting the service to get killed mid call, so a DeadObjectException
|
||||
// is not unexpected
|
||||
}
|
||||
|
||||
if (!binderDeathLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
|
||||
sBpcTestAppCmdService.releaseSystemBinders(exceedBinderProxyLimit);
|
||||
fail("Timed out waiting for uid " + sTestPkgUid + " to die.");
|
||||
}
|
||||
|
||||
} finally {
|
||||
unbindService(sTestAppConnection);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -380,6 +380,7 @@ import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
|
||||
import com.android.internal.notification.SystemNotificationChannels;
|
||||
import com.android.internal.os.BackgroundThread;
|
||||
import com.android.internal.os.BatteryStatsImpl;
|
||||
import com.android.internal.os.BinderInternal;
|
||||
import com.android.internal.os.IResultReceiver;
|
||||
import com.android.internal.os.ProcessCpuTracker;
|
||||
import com.android.internal.os.TransferPipe;
|
||||
@@ -14366,6 +14367,23 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
}
|
||||
mStackSupervisor.resumeFocusedStackTopActivityLocked();
|
||||
mUserController.sendUserSwitchBroadcastsLocked(-1, currentUserId);
|
||||
|
||||
BinderInternal.nSetBinderProxyCountEnabled(true);
|
||||
BinderInternal.setBinderProxyCountCallback(
|
||||
new BinderInternal.BinderProxyLimitListener() {
|
||||
@Override
|
||||
public void onLimitReached(int uid) {
|
||||
Slog.wtf(TAG, "Uid " + uid + " sent too many Binders to uid "
|
||||
+ Process.myUid());
|
||||
if (uid == Process.SYSTEM_UID) {
|
||||
Slog.i(TAG, "Skipping kill (uid is SYSTEM)");
|
||||
} else {
|
||||
killUid(UserHandle.getAppId(uid), UserHandle.getUserId(uid),
|
||||
"Too many Binders sent to SYSTEM");
|
||||
}
|
||||
}
|
||||
}, mHandler);
|
||||
|
||||
traceLog.traceEnd(); // ActivityManagerStartApps
|
||||
traceLog.traceEnd(); // PhaseActivityManagerReady
|
||||
}
|
||||
@@ -15134,6 +15152,19 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
synchronized (this) {
|
||||
dumpRecentsLocked(fd, pw, args, opti, true, dumpPackage);
|
||||
}
|
||||
} else if ("binder-proxies".equals(cmd)) {
|
||||
if (opti >= args.length) {
|
||||
dumpBinderProxiesCounts(pw, BinderInternal.nGetBinderProxyPerUidCounts(),
|
||||
"Counts of Binder Proxies held by SYSTEM");
|
||||
} else {
|
||||
String uid = args[opti];
|
||||
opti++;
|
||||
// Ensure Binder Proxy Count is as up to date as possible
|
||||
System.gc();
|
||||
System.runFinalization();
|
||||
System.gc();
|
||||
pw.println(BinderInternal.nGetBinderProxyCount(Integer.parseInt(uid)));
|
||||
}
|
||||
} else if ("broadcasts".equals(cmd) || "b".equals(cmd)) {
|
||||
String[] newArgs;
|
||||
String name;
|
||||
@@ -15663,6 +15694,34 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
return printed;
|
||||
}
|
||||
|
||||
boolean dumpBinderProxiesCounts(PrintWriter pw, SparseIntArray counts, String header) {
|
||||
if(counts != null) {
|
||||
pw.println(header);
|
||||
for (int i = 0; i < counts.size(); i++) {
|
||||
final int uid = counts.keyAt(i);
|
||||
final int binderCount = counts.valueAt(i);
|
||||
pw.print(" UID ");
|
||||
pw.print(uid);
|
||||
pw.print(", binder count = ");
|
||||
pw.print(binderCount);
|
||||
pw.print(", package(s)= ");
|
||||
final String[] pkgNames = mContext.getPackageManager().getPackagesForUid(uid);
|
||||
if (pkgNames != null) {
|
||||
for (int j = 0; j < pkgNames.length; j++) {
|
||||
pw.print(pkgNames[j]);
|
||||
pw.print("; ");
|
||||
}
|
||||
} else {
|
||||
pw.print("NO PACKAGE NAME FOUND");
|
||||
}
|
||||
pw.println();
|
||||
}
|
||||
pw.println();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void dumpProcessesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
|
||||
int opti, boolean dumpAll, String dumpPackage) {
|
||||
boolean needSep = false;
|
||||
|
||||
Reference in New Issue
Block a user