Merge changes from topic "aug31"
* changes: [4/?] Tests for generic BroadcastQueue. [3/?] Tests for generic BroadcastQueue. [2/?] Tests for generic BroadcastQueue.
This commit is contained in:
@@ -35,7 +35,9 @@ import android.app.BroadcastOptions;
|
||||
import android.app.IApplicationThread;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.IIntentReceiver;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManagerInternal;
|
||||
@@ -48,6 +50,7 @@ import android.os.SystemClock;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import androidx.test.filters.MediumTest;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
@@ -71,12 +74,14 @@ import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* Common tests for {@link BroadcastQueue} implementations.
|
||||
*/
|
||||
@MediumTest
|
||||
@RunWith(Parameterized.class)
|
||||
@SuppressWarnings("GuardedBy")
|
||||
public class BroadcastQueueTest {
|
||||
private static final String TAG = "BroadcastQueueTest";
|
||||
|
||||
@@ -92,15 +97,23 @@ public class BroadcastQueueTest {
|
||||
|
||||
private Context mContext;
|
||||
private HandlerThread mHandlerThread;
|
||||
private AtomicInteger mNextPid;
|
||||
|
||||
@Mock
|
||||
private AppOpsService mAppOpsService;
|
||||
@Mock
|
||||
private ProcessList mProcessList;
|
||||
@Mock
|
||||
private PackageManagerInternal mPackageManagerInt;
|
||||
|
||||
private ActivityManagerService mAms;
|
||||
private BroadcastQueue mQueue;
|
||||
|
||||
/**
|
||||
* Map from PID to registered registered runtime receivers.
|
||||
*/
|
||||
private SparseArray<ReceiverList> mRegisteredReceivers = new SparseArray<>();
|
||||
|
||||
@Parameters(name = "impl={0}")
|
||||
public static Collection<Object[]> data() {
|
||||
return Arrays.asList(new Object[][] { {Impl.DEFAULT} });
|
||||
@@ -118,6 +131,7 @@ public class BroadcastQueueTest {
|
||||
|
||||
mHandlerThread = new HandlerThread(TAG);
|
||||
mHandlerThread.start();
|
||||
mNextPid = new AtomicInteger(100);
|
||||
|
||||
LocalServices.removeServiceForTest(PackageManagerInternal.class);
|
||||
LocalServices.addService(PackageManagerInternal.class, mPackageManagerInt);
|
||||
@@ -131,6 +145,18 @@ public class BroadcastQueueTest {
|
||||
realAms.mAtmInternal = spy(realAms.mActivityTaskManager.getAtmInternal());
|
||||
realAms.mPackageManagerInt = mPackageManagerInt;
|
||||
mAms = spy(realAms);
|
||||
doAnswer((invocation) -> {
|
||||
Log.v(TAG, "Intercepting startProcessLocked() for "
|
||||
+ Arrays.toString(invocation.getArguments()));
|
||||
final String processName = invocation.getArgument(0);
|
||||
final ApplicationInfo ai = invocation.getArgument(1);
|
||||
final ProcessRecord res = makeActiveProcessRecord(ai, processName);
|
||||
mHandlerThread.getThreadHandler().post(() -> {
|
||||
mQueue.onApplicationAttachedLocked(res);
|
||||
});
|
||||
return res;
|
||||
}).when(mAms).startProcessLocked(any(), any(), anyBoolean(), anyInt(),
|
||||
any(), anyInt(), anyBoolean(), anyBoolean());
|
||||
|
||||
final BroadcastConstants constants = new BroadcastConstants(
|
||||
Settings.Global.BROADCAST_FG_CONSTANTS);
|
||||
@@ -165,33 +191,65 @@ public class BroadcastQueueTest {
|
||||
public Handler getUiHandler(ActivityManagerService service) {
|
||||
return mHandlerThread.getThreadHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProcessList getProcessList(ActivityManagerService service) {
|
||||
return mProcessList;
|
||||
}
|
||||
}
|
||||
|
||||
private ProcessRecord makeActiveProcessRecord(String packageName) throws Exception {
|
||||
final ProcessRecord r = new ProcessRecord(mAms, makeApplicationInfo(packageName), null,
|
||||
getUidForPackage(packageName));
|
||||
final ApplicationInfo ai = makeApplicationInfo(packageName);
|
||||
return makeActiveProcessRecord(ai, ai.processName);
|
||||
}
|
||||
|
||||
private ProcessRecord makeActiveProcessRecord(ApplicationInfo ai, String processName)
|
||||
throws Exception {
|
||||
final ProcessRecord r = new ProcessRecord(mAms, ai, processName, ai.uid);
|
||||
r.setPid(mNextPid.getAndIncrement());
|
||||
|
||||
final IApplicationThread thread = mock(IApplicationThread.class);
|
||||
final IBinder threadBinder = new Binder();
|
||||
doReturn(threadBinder).when(thread).asBinder();
|
||||
r.makeActive(thread, mAms.mProcessStats);
|
||||
|
||||
doReturn(r).when(mAms).getProcessRecordLocked(eq(r.info.processName), eq(r.info.uid));
|
||||
|
||||
final IIntentReceiver receiver = mock(IIntentReceiver.class);
|
||||
final IBinder receiverBinder = new Binder();
|
||||
doReturn(receiverBinder).when(receiver).asBinder();
|
||||
final ReceiverList receiverList = new ReceiverList(mAms, r, r.getPid(), r.info.uid,
|
||||
UserHandle.getUserId(r.info.uid), receiver);
|
||||
mRegisteredReceivers.put(r.getPid(), receiverList);
|
||||
|
||||
doAnswer((invocation) -> {
|
||||
Log.v(TAG, "Delivering finishReceiverLocked() for "
|
||||
Log.v(TAG, "Intercepting scheduleReceiver() for "
|
||||
+ Arrays.toString(invocation.getArguments()));
|
||||
mQueue.finishReceiverLocked(threadBinder, Activity.RESULT_OK,
|
||||
null, null, false, false);
|
||||
mHandlerThread.getThreadHandler().post(() -> {
|
||||
mQueue.finishReceiverLocked(threadBinder, Activity.RESULT_OK,
|
||||
null, null, false, false);
|
||||
});
|
||||
return null;
|
||||
}).when(thread).scheduleReceiver(any(), any(), any(), anyInt(), any(), any(), anyBoolean(),
|
||||
anyInt(), anyInt());
|
||||
|
||||
doAnswer((invocation) -> {
|
||||
Log.v(TAG, "Intercepting scheduleRegisteredReceiver() for "
|
||||
+ Arrays.toString(invocation.getArguments()));
|
||||
mHandlerThread.getThreadHandler().post(() -> {
|
||||
mQueue.finishReceiverLocked(receiverBinder, Activity.RESULT_OK, null, null,
|
||||
false, false);
|
||||
});
|
||||
return null;
|
||||
}).when(thread).scheduleRegisteredReceiver(any(), any(), anyInt(), any(), any(),
|
||||
anyBoolean(), anyBoolean(), anyInt(), anyInt());
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
private ApplicationInfo makeApplicationInfo(String packageName) {
|
||||
final ApplicationInfo ai = new ApplicationInfo();
|
||||
ai.packageName = packageName;
|
||||
ai.processName = packageName;
|
||||
ai.uid = getUidForPackage(packageName);
|
||||
return ai;
|
||||
}
|
||||
@@ -200,11 +258,22 @@ public class BroadcastQueueTest {
|
||||
final ResolveInfo ri = new ResolveInfo();
|
||||
ri.activityInfo = new ActivityInfo();
|
||||
ri.activityInfo.packageName = packageName;
|
||||
ri.activityInfo.processName = packageName;
|
||||
ri.activityInfo.name = name;
|
||||
ri.activityInfo.applicationInfo = makeApplicationInfo(packageName);
|
||||
return ri;
|
||||
}
|
||||
|
||||
private BroadcastFilter makeRegisteredReceiver(ProcessRecord app) {
|
||||
final ReceiverList receiverList = mRegisteredReceivers.get(app.getPid());
|
||||
final IntentFilter filter = new IntentFilter();
|
||||
final BroadcastFilter res = new BroadcastFilter(filter, receiverList,
|
||||
receiverList.app.info.packageName, null, null, null, receiverList.uid,
|
||||
receiverList.userId, false, false, true);
|
||||
receiverList.add(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
private BroadcastRecord makeBroadcastRecord(Intent intent, ProcessRecord callerApp,
|
||||
List receivers) {
|
||||
return makeBroadcastRecord(intent, callerApp, BroadcastOptions.makeBasic(), receivers);
|
||||
@@ -236,23 +305,43 @@ public class BroadcastQueueTest {
|
||||
assertTrue(mQueue.isIdle());
|
||||
}
|
||||
|
||||
private void verifyScheduleReceiver(ProcessRecord app, Intent intent) throws Exception {
|
||||
verify(app.getThread()).scheduleReceiver(
|
||||
argThat(filterEqualsIgnoringComponent(intent)), any(), any(), anyInt(), any(),
|
||||
any(), eq(false), eq(UserHandle.USER_SYSTEM), anyInt());
|
||||
}
|
||||
|
||||
private void verifyScheduleRegisteredReceiver(ProcessRecord app, Intent intent)
|
||||
throws Exception {
|
||||
verify(app.getThread()).scheduleRegisteredReceiver(any(),
|
||||
argThat(filterEqualsIgnoringComponent(intent)), anyInt(), any(), any(),
|
||||
anyBoolean(), anyBoolean(), eq(UserHandle.USER_SYSTEM), anyInt());
|
||||
}
|
||||
|
||||
private static final String PACKAGE_RED = "com.example.red";
|
||||
private static final String PACKAGE_GREEN = "com.example.green";
|
||||
private static final String PACKAGE_BLUE = "com.example.blue";
|
||||
private static final String PACKAGE_YELLOW = "com.example.yellow";
|
||||
|
||||
private static final String CLASS_RED = "com.example.red.Red";
|
||||
private static final String CLASS_GREEN = "com.example.green.Green";
|
||||
private static final String CLASS_BLUE = "com.example.blue.Blue";
|
||||
private static final String CLASS_YELLOW = "com.example.yellow.Yellow";
|
||||
|
||||
private static int getUidForPackage(String packageName) {
|
||||
switch (packageName) {
|
||||
case PACKAGE_RED: return android.os.Process.FIRST_APPLICATION_UID + 1;
|
||||
case PACKAGE_GREEN: return android.os.Process.FIRST_APPLICATION_UID + 2;
|
||||
case PACKAGE_BLUE: return android.os.Process.FIRST_APPLICATION_UID + 3;
|
||||
case PACKAGE_YELLOW: return android.os.Process.FIRST_APPLICATION_UID + 4;
|
||||
default: throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify dispatch of simple broadcast to single manifest receiver in
|
||||
* already-running warm app.
|
||||
*/
|
||||
@Test
|
||||
public void testSimple_Manifest_Warm() throws Exception {
|
||||
final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
|
||||
@@ -263,11 +352,13 @@ public class BroadcastQueueTest {
|
||||
List.of(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN))));
|
||||
|
||||
waitForIdle();
|
||||
verify(receiverApp.getThread()).scheduleReceiver(
|
||||
argThat(filterEqualsIgnoringComponent(intent)), any(), any(), anyInt(), any(),
|
||||
any(), eq(false), eq(UserHandle.USER_SYSTEM), anyInt());
|
||||
verifyScheduleReceiver(receiverApp, intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify dispatch of multiple broadcasts to multiple manifest receivers in
|
||||
* already-running warm apps.
|
||||
*/
|
||||
@Test
|
||||
public void testSimple_Manifest_Warm_Multiple() throws Exception {
|
||||
final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
|
||||
@@ -285,20 +376,114 @@ public class BroadcastQueueTest {
|
||||
List.of(makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE))));
|
||||
|
||||
waitForIdle();
|
||||
verify(receiverGreenApp.getThread()).scheduleReceiver(
|
||||
argThat(filterEqualsIgnoringComponent(timezone)), any(), any(), anyInt(), any(),
|
||||
any(), eq(false), eq(UserHandle.USER_SYSTEM), anyInt());
|
||||
verify(receiverBlueApp.getThread()).scheduleReceiver(
|
||||
argThat(filterEqualsIgnoringComponent(timezone)), any(), any(), anyInt(), any(),
|
||||
any(), eq(false), eq(UserHandle.USER_SYSTEM), anyInt());
|
||||
verify(receiverBlueApp.getThread()).scheduleReceiver(
|
||||
argThat(filterEqualsIgnoringComponent(airplane)), any(), any(), anyInt(), any(),
|
||||
any(), eq(false), eq(UserHandle.USER_SYSTEM), anyInt());
|
||||
verifyScheduleReceiver(receiverGreenApp, timezone);
|
||||
verifyScheduleReceiver(receiverBlueApp, timezone);
|
||||
verifyScheduleReceiver(receiverBlueApp, airplane);
|
||||
}
|
||||
|
||||
// TODO: verify registered receiver in warm app
|
||||
// TODO: verify manifest receiver in cold app
|
||||
/**
|
||||
* Verify dispatch of multiple broadcast to multiple manifest receivers in
|
||||
* apps that require cold starts.
|
||||
*/
|
||||
@Test
|
||||
public void testSimple_Manifest_ColdThenWarm() throws Exception {
|
||||
final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
|
||||
|
||||
// TODO: verify mixing multiple manifest and registered receivers of same broadcast
|
||||
// TODO: verify delivery of 3 distinct broadcasts
|
||||
// We purposefully dispatch into green twice; the first time cold and
|
||||
// the second time it should already be running
|
||||
|
||||
final Intent timezone = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
|
||||
mQueue.enqueueBroadcastLocked(makeBroadcastRecord(timezone, callerApp,
|
||||
List.of(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN),
|
||||
makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE))));
|
||||
|
||||
final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
|
||||
mQueue.enqueueBroadcastLocked(makeBroadcastRecord(airplane, callerApp,
|
||||
List.of(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN))));
|
||||
|
||||
waitForIdle();
|
||||
final ProcessRecord receiverGreenApp = mAms.getProcessRecordLocked(PACKAGE_GREEN,
|
||||
getUidForPackage(PACKAGE_GREEN));
|
||||
final ProcessRecord receiverBlueApp = mAms.getProcessRecordLocked(PACKAGE_BLUE,
|
||||
getUidForPackage(PACKAGE_BLUE));
|
||||
assertTrue(receiverBlueApp.getPid() > receiverGreenApp.getPid());
|
||||
verifyScheduleReceiver(receiverGreenApp, timezone);
|
||||
verifyScheduleReceiver(receiverGreenApp, airplane);
|
||||
verifyScheduleReceiver(receiverBlueApp, timezone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify dispatch of simple broadcast to single registered receiver in
|
||||
* already-running warm app.
|
||||
*/
|
||||
@Test
|
||||
public void testSimple_Registered() throws Exception {
|
||||
final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
|
||||
final ProcessRecord receiverApp = makeActiveProcessRecord(PACKAGE_GREEN);
|
||||
|
||||
final Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
|
||||
mQueue.enqueueBroadcastLocked(makeBroadcastRecord(intent, callerApp,
|
||||
List.of(makeRegisteredReceiver(receiverApp))));
|
||||
|
||||
waitForIdle();
|
||||
verifyScheduleRegisteredReceiver(receiverApp, intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify dispatch of multiple broadcasts to multiple registered receivers
|
||||
* in already-running warm apps.
|
||||
*/
|
||||
@Test
|
||||
public void testSimple_Registered_Multiple() throws Exception {
|
||||
final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
|
||||
|
||||
final ProcessRecord receiverGreenApp = makeActiveProcessRecord(PACKAGE_GREEN);
|
||||
final ProcessRecord receiverBlueApp = makeActiveProcessRecord(PACKAGE_BLUE);
|
||||
|
||||
final Intent timezone = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
|
||||
mQueue.enqueueBroadcastLocked(makeBroadcastRecord(timezone, callerApp,
|
||||
List.of(makeRegisteredReceiver(receiverGreenApp),
|
||||
makeRegisteredReceiver(receiverBlueApp))));
|
||||
|
||||
final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
|
||||
mQueue.enqueueBroadcastLocked(makeBroadcastRecord(airplane, callerApp,
|
||||
List.of(makeRegisteredReceiver(receiverBlueApp))));
|
||||
|
||||
waitForIdle();
|
||||
verifyScheduleRegisteredReceiver(receiverGreenApp, timezone);
|
||||
verifyScheduleRegisteredReceiver(receiverBlueApp, timezone);
|
||||
verifyScheduleRegisteredReceiver(receiverBlueApp, airplane);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify dispatch of multiple broadcasts mixed to both manifest and
|
||||
* registered receivers, to both warm and cold apps.
|
||||
*/
|
||||
@Test
|
||||
public void testComplex() throws Exception {
|
||||
final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
|
||||
|
||||
final ProcessRecord receiverGreenApp = makeActiveProcessRecord(PACKAGE_GREEN);
|
||||
final ProcessRecord receiverYellowApp = makeActiveProcessRecord(PACKAGE_YELLOW);
|
||||
|
||||
final Intent timezone = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
|
||||
mQueue.enqueueBroadcastLocked(makeBroadcastRecord(timezone, callerApp,
|
||||
List.of(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN),
|
||||
makeRegisteredReceiver(receiverGreenApp),
|
||||
makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE),
|
||||
makeRegisteredReceiver(receiverYellowApp))));
|
||||
|
||||
final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
|
||||
mQueue.enqueueBroadcastLocked(makeBroadcastRecord(airplane, callerApp,
|
||||
List.of(makeManifestReceiver(PACKAGE_YELLOW, CLASS_YELLOW))));
|
||||
|
||||
waitForIdle();
|
||||
final ProcessRecord receiverBlueApp = mAms.getProcessRecordLocked(PACKAGE_BLUE,
|
||||
getUidForPackage(PACKAGE_BLUE));
|
||||
verifyScheduleReceiver(receiverGreenApp, timezone);
|
||||
verifyScheduleRegisteredReceiver(receiverGreenApp, timezone);
|
||||
verifyScheduleReceiver(receiverBlueApp, timezone);
|
||||
verifyScheduleRegisteredReceiver(receiverYellowApp, timezone);
|
||||
verifyScheduleReceiver(receiverYellowApp, airplane);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user