Supplying the IBinder to binderDied
Plugging the binder instance that dies. This helps a single DeathRecipient to listen for multiple binder deaths. Test: atest FrameworksCoreTests:BinderDeathRecipientTest Bug: 135633339 Change-Id: I976ee2a138877830885ee1cbbd2b313ecb87aeb3
This commit is contained in:
@@ -631,10 +631,12 @@ public final class BinderProxy implements IBinder {
|
||||
}
|
||||
}
|
||||
|
||||
private static void sendDeathNotice(DeathRecipient recipient) {
|
||||
if (false) Log.v("JavaBinder", "sendDeathNotice to " + recipient);
|
||||
private static void sendDeathNotice(DeathRecipient recipient, IBinder binderProxy) {
|
||||
if (false) {
|
||||
Log.v("JavaBinder", "sendDeathNotice to " + recipient + " for " + binderProxy);
|
||||
}
|
||||
try {
|
||||
recipient.binderDied();
|
||||
recipient.binderDied(binderProxy);
|
||||
} catch (RuntimeException exc) {
|
||||
Log.w("BinderNative", "Uncaught exception from death notification",
|
||||
exc);
|
||||
|
||||
@@ -285,6 +285,13 @@ public interface IBinder {
|
||||
*/
|
||||
public interface DeathRecipient {
|
||||
public void binderDied();
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
default void binderDied(IBinder who) {
|
||||
binderDied();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -537,9 +537,9 @@ public:
|
||||
LOGDEATH("Receiving binderDied() on JavaDeathRecipient %p\n", this);
|
||||
if (mObject != NULL) {
|
||||
JNIEnv* env = javavm_to_jnienv(mVM);
|
||||
|
||||
jobject jBinderProxy = javaObjectForIBinder(env, who.promote());
|
||||
env->CallStaticVoidMethod(gBinderProxyOffsets.mClass,
|
||||
gBinderProxyOffsets.mSendDeathNotice, mObject);
|
||||
gBinderProxyOffsets.mSendDeathNotice, mObject, jBinderProxy);
|
||||
if (env->ExceptionCheck()) {
|
||||
jthrowable excep = env->ExceptionOccurred();
|
||||
report_exception(env, excep,
|
||||
@@ -1532,8 +1532,9 @@ static int int_register_android_os_BinderProxy(JNIEnv* env)
|
||||
gBinderProxyOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
|
||||
gBinderProxyOffsets.mGetInstance = GetStaticMethodIDOrDie(env, clazz, "getInstance",
|
||||
"(JJ)Landroid/os/BinderProxy;");
|
||||
gBinderProxyOffsets.mSendDeathNotice = GetStaticMethodIDOrDie(env, clazz, "sendDeathNotice",
|
||||
"(Landroid/os/IBinder$DeathRecipient;)V");
|
||||
gBinderProxyOffsets.mSendDeathNotice =
|
||||
GetStaticMethodIDOrDie(env, clazz, "sendDeathNotice",
|
||||
"(Landroid/os/IBinder$DeathRecipient;Landroid/os/IBinder;)V");
|
||||
gBinderProxyOffsets.mNativeData = GetFieldIDOrDie(env, clazz, "mNativeData", "J");
|
||||
|
||||
clazz = FindClassOrDie(env, "java/lang/Class");
|
||||
|
||||
@@ -8,6 +8,7 @@ android_test {
|
||||
"EnabledTestApp/src/**/*.java",
|
||||
"BinderProxyCountingTestApp/src/**/*.java",
|
||||
"BinderProxyCountingTestService/src/**/*.java",
|
||||
"BinderDeathRecipientHelperApp/src/**/*.java",
|
||||
"aidl/**/I*.aidl",
|
||||
],
|
||||
|
||||
@@ -59,7 +60,11 @@ android_test {
|
||||
resource_dirs: ["res"],
|
||||
resource_zips: [":FrameworksCoreTests_apks_as_resources"],
|
||||
|
||||
data: [":BstatsTestApp"],
|
||||
data: [
|
||||
":BstatsTestApp",
|
||||
":BinderDeathRecipientHelperApp1",
|
||||
":BinderDeathRecipientHelperApp2",
|
||||
],
|
||||
}
|
||||
|
||||
// Rules to copy all the test apks to the intermediate raw resource directory
|
||||
|
||||
@@ -95,6 +95,7 @@
|
||||
|
||||
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
|
||||
<uses-permission android:name="android.permission.KILL_UID" />
|
||||
<uses-permission android:name="android.permission.FORCE_STOP_PACKAGES" />
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
<option name="cleanup-apks" value="true" />
|
||||
<option name="test-file-name" value="FrameworksCoreTests.apk" />
|
||||
<option name="test-file-name" value="BstatsTestApp.apk" />
|
||||
<option name="test-file-name" value="BinderDeathRecipientHelperApp1.apk" />
|
||||
<option name="test-file-name" value="BinderDeathRecipientHelperApp2.apk" />
|
||||
</target_preparer>
|
||||
<option name="test-tag" value="FrameworksCoreTests" />
|
||||
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
android_test_helper_app {
|
||||
name: "BinderDeathRecipientHelperApp1",
|
||||
|
||||
srcs: ["**/*.java"],
|
||||
|
||||
sdk_version: "current",
|
||||
}
|
||||
|
||||
android_test_helper_app {
|
||||
name: "BinderDeathRecipientHelperApp2",
|
||||
|
||||
srcs: ["**/*.java"],
|
||||
|
||||
sdk_version: "current",
|
||||
|
||||
aaptflags: [
|
||||
"--rename-manifest-package com.android.frameworks.coretests.bdr_helper_app2",
|
||||
],
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2020 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.bdr_helper_app1">
|
||||
|
||||
<application>
|
||||
<receiver android:name="com.android.frameworks.coretests.bdr_helper_app.TestCommsReceiver"
|
||||
android:exported="true"/>
|
||||
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.bdr_helper_app;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Receiver used to hand off a binder owned by this process to
|
||||
* {@link android.os.BinderDeathRecipientTest}.
|
||||
*/
|
||||
public class TestCommsReceiver extends BroadcastReceiver {
|
||||
private static final String TAG = TestCommsReceiver.class.getSimpleName();
|
||||
private static final String PACKAGE_NAME = "com.android.frameworks.coretests.bdr_helper_app";
|
||||
|
||||
public static final String ACTION_GET_BINDER = PACKAGE_NAME + ".action.GET_BINDER";
|
||||
public static final String EXTRA_KEY_BINDER = PACKAGE_NAME + ".EXTRA_BINDER";
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
switch (intent.getAction()) {
|
||||
case ACTION_GET_BINDER:
|
||||
final Bundle resultExtras = new Bundle();
|
||||
resultExtras.putBinder(EXTRA_KEY_BINDER, new Binder());
|
||||
setResult(Activity.RESULT_OK, null, resultExtras);
|
||||
break;
|
||||
default:
|
||||
Log.e(TAG, "Unknown action " + intent.getAction());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.frameworks.coretests.bdr_helper_app.TestCommsReceiver;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.BrokenBarrierException;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.CyclicBarrier;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* Tests functionality of {@link android.os.IBinder.DeathRecipient} callbacks.
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class BinderDeathRecipientTest {
|
||||
private static final String TAG = BinderDeathRecipientTest.class.getSimpleName();
|
||||
private static final String TEST_PACKAGE_NAME_1 =
|
||||
"com.android.frameworks.coretests.bdr_helper_app1";
|
||||
private static final String TEST_PACKAGE_NAME_2 =
|
||||
"com.android.frameworks.coretests.bdr_helper_app2";
|
||||
|
||||
private Context mContext;
|
||||
private Handler mHandler;
|
||||
private ActivityManager mActivityManager;
|
||||
private Set<Pair<IBinder, IBinder.DeathRecipient>> mLinkedDeathRecipients = new ArraySet<>();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = InstrumentationRegistry.getTargetContext();
|
||||
mActivityManager = mContext.getSystemService(ActivityManager.class);
|
||||
mHandler = new Handler(Looper.getMainLooper());
|
||||
}
|
||||
|
||||
private IBinder getNewRemoteBinder(String testPackage) throws InterruptedException {
|
||||
final CountDownLatch resultLatch = new CountDownLatch(1);
|
||||
final AtomicInteger resultCode = new AtomicInteger(Activity.RESULT_CANCELED);
|
||||
final AtomicReference<Bundle> resultExtras = new AtomicReference<>();
|
||||
|
||||
final Intent intent = new Intent(TestCommsReceiver.ACTION_GET_BINDER)
|
||||
.setClassName(testPackage, TestCommsReceiver.class.getName());
|
||||
mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
resultCode.set(getResultCode());
|
||||
resultExtras.set(getResultExtras(true));
|
||||
resultLatch.countDown();
|
||||
}
|
||||
}, mHandler, Activity.RESULT_CANCELED, null, null);
|
||||
|
||||
assertTrue("Request for binder timed out", resultLatch.await(5, TimeUnit.SECONDS));
|
||||
assertEquals(Activity.RESULT_OK, resultCode.get());
|
||||
return resultExtras.get().getBinder(TestCommsReceiver.EXTRA_KEY_BINDER);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void binderDied_noArgs() throws Exception {
|
||||
final IBinder testAppBinder = getNewRemoteBinder(TEST_PACKAGE_NAME_1);
|
||||
final CountDownLatch deathNotificationLatch = new CountDownLatch(1);
|
||||
final IBinder.DeathRecipient simpleDeathRecipient =
|
||||
() -> deathNotificationLatch.countDown();
|
||||
testAppBinder.linkToDeath(simpleDeathRecipient, 0);
|
||||
mLinkedDeathRecipients.add(Pair.create(testAppBinder, simpleDeathRecipient));
|
||||
|
||||
mActivityManager.forceStopPackage(TEST_PACKAGE_NAME_1);
|
||||
assertTrue("Death notification did not arrive",
|
||||
deathNotificationLatch.await(10, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void binderDied_iBinderArg() throws Exception {
|
||||
final IBinder testApp1Binder = getNewRemoteBinder(TEST_PACKAGE_NAME_1);
|
||||
final IBinder testApp2Binder = getNewRemoteBinder(TEST_PACKAGE_NAME_2);
|
||||
final CyclicBarrier barrier = new CyclicBarrier(2);
|
||||
|
||||
final AtomicReference<IBinder> binderThatDied = new AtomicReference<>();
|
||||
final IBinder.DeathRecipient sameDeathRecipient = new IBinder.DeathRecipient() {
|
||||
@Override
|
||||
public void binderDied() {
|
||||
Log.e(TAG, "Should not have been called!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void binderDied(IBinder who) {
|
||||
binderThatDied.set(who);
|
||||
try {
|
||||
barrier.await();
|
||||
} catch (InterruptedException | BrokenBarrierException e) {
|
||||
Log.e(TAG, "Unexpected exception while waiting on CyclicBarrier", e);
|
||||
}
|
||||
}
|
||||
};
|
||||
testApp1Binder.linkToDeath(sameDeathRecipient, 0);
|
||||
mLinkedDeathRecipients.add(Pair.create(testApp1Binder, sameDeathRecipient));
|
||||
|
||||
testApp2Binder.linkToDeath(sameDeathRecipient, 0);
|
||||
mLinkedDeathRecipients.add(Pair.create(testApp2Binder, sameDeathRecipient));
|
||||
|
||||
mActivityManager.forceStopPackage(TEST_PACKAGE_NAME_1);
|
||||
try {
|
||||
barrier.await(10, TimeUnit.SECONDS);
|
||||
} catch (TimeoutException e) {
|
||||
fail("Timed out while waiting for 1st death notification: " + e.getMessage());
|
||||
}
|
||||
assertEquals("Different binder received", testApp1Binder, binderThatDied.get());
|
||||
|
||||
barrier.reset();
|
||||
mActivityManager.forceStopPackage(TEST_PACKAGE_NAME_2);
|
||||
try {
|
||||
barrier.await(10, TimeUnit.SECONDS);
|
||||
} catch (TimeoutException e) {
|
||||
fail("Timed out while waiting for 2nd death notification: " + e.getMessage());
|
||||
}
|
||||
assertEquals("Different binder received", testApp2Binder, binderThatDied.get());
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
for (Pair<IBinder, IBinder.DeathRecipient> linkedPair : mLinkedDeathRecipients) {
|
||||
linkedPair.first.unlinkToDeath(linkedPair.second, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user