blob: f44104e10967f00b2c96fd98d408dcedbd0bc4fb [file] [log] [blame]
/*
* Copyright (C) 2018 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.server.am;
import static org.junit.Assert.assertNull;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ResolveInfo;
import android.os.Process;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Test class for {@link BroadcastRecord}.
*
* Build/Install/Run:
* atest FrameworksServicesTests:BroadcastRecordTest
*/
@SmallTest
@Presubmit
public class BroadcastRecordTest {
@Test
public void testCleanupDisabledPackageReceivers() {
final int user0 = UserHandle.USER_SYSTEM;
final int user1 = user0 + 1;
final String pkgToCleanup = "pkg.a";
final String pkgOther = "pkg.b";
// Receivers contain multiple-user (contains [pkg.a@u0, pkg.a@u1, pkg.b@u0, pkg.b@u1]).
final List<ResolveInfo> receiversM = createReceiverInfos(
new String[] { pkgToCleanup, pkgOther },
new int[] { user0, user1 });
// Receivers only contain one user (contains [pkg.a@u0, pkg.b@u0]).
final List<ResolveInfo> receiversU0 = excludeReceivers(
receiversM, null /* packageName */, user1);
// With given package:
// Send to all users, cleanup a package of all users.
final BroadcastRecord recordAllAll = createBroadcastRecord(receiversM, UserHandle.USER_ALL);
cleanupDisabledPackageReceivers(recordAllAll, pkgToCleanup, UserHandle.USER_ALL);
assertNull(verifyRemaining(recordAllAll, excludeReceivers(receiversM, pkgToCleanup, -1)));
// Send to all users, cleanup a package of one user.
final BroadcastRecord recordAllOne = createBroadcastRecord(receiversM, UserHandle.USER_ALL);
cleanupDisabledPackageReceivers(recordAllOne, pkgToCleanup, user0);
assertNull(verifyRemaining(recordAllOne,
excludeReceivers(receiversM, pkgToCleanup, user0)));
// Send to one user, cleanup a package of all users.
final BroadcastRecord recordOneAll = createBroadcastRecord(receiversU0, user0);
cleanupDisabledPackageReceivers(recordOneAll, pkgToCleanup, UserHandle.USER_ALL);
assertNull(verifyRemaining(recordOneAll, excludeReceivers(receiversU0, pkgToCleanup, -1)));
// Send to one user, cleanup a package one user.
final BroadcastRecord recordOneOne = createBroadcastRecord(receiversU0, user0);
cleanupDisabledPackageReceivers(recordOneOne, pkgToCleanup, user0);
assertNull(verifyRemaining(recordOneOne, excludeReceivers(receiversU0, pkgToCleanup, -1)));
// Without given package (e.g. stop user):
// Send to all users, cleanup one user.
final BroadcastRecord recordAllM = createBroadcastRecord(receiversM, UserHandle.USER_ALL);
cleanupDisabledPackageReceivers(recordAllM, null /* packageName */, user1);
assertNull(verifyRemaining(recordAllM,
excludeReceivers(receiversM, null /* packageName */, user1)));
// Send to one user, cleanup one user.
final BroadcastRecord recordU0 = createBroadcastRecord(receiversU0, user0);
cleanupDisabledPackageReceivers(recordU0, null /* packageName */, user0);
assertNull(verifyRemaining(recordU0, Collections.emptyList()));
}
private static void cleanupDisabledPackageReceivers(BroadcastRecord record,
String packageName, int userId) {
record.cleanupDisabledPackageReceiversLocked(packageName, null /* filterByClasses */,
userId, true /* doit */);
}
private static String verifyRemaining(BroadcastRecord record,
List<ResolveInfo> expectedRemainingReceivers) {
final StringBuilder errorMsg = new StringBuilder();
for (final Object receiver : record.receivers) {
final ResolveInfo resolveInfo = (ResolveInfo) receiver;
final ApplicationInfo appInfo = resolveInfo.activityInfo.applicationInfo;
boolean foundExpected = false;
for (final ResolveInfo expectedReceiver : expectedRemainingReceivers) {
final ApplicationInfo expectedAppInfo =
expectedReceiver.activityInfo.applicationInfo;
if (appInfo.packageName.equals(expectedAppInfo.packageName)
&& UserHandle.getUserId(appInfo.uid) == UserHandle
.getUserId(expectedAppInfo.uid)) {
foundExpected = true;
break;
}
}
if (!foundExpected) {
errorMsg.append(appInfo.packageName).append("@")
.append('u').append(UserHandle.getUserId(appInfo.uid)).append(' ');
}
}
return errorMsg.length() == 0 ? null
: errorMsg.insert(0, "Contains unexpected receiver: ").toString();
}
private static ResolveInfo createResolveInfo(String packageName, int uid) {
final ResolveInfo resolveInfo = new ResolveInfo();
final ActivityInfo activityInfo = new ActivityInfo();
final ApplicationInfo appInfo = new ApplicationInfo();
appInfo.packageName = packageName;
appInfo.uid = uid;
activityInfo.applicationInfo = appInfo;
resolveInfo.activityInfo = activityInfo;
return resolveInfo;
}
/**
* Generate (packages.length * userIds.length) receivers.
*/
private static List<ResolveInfo> createReceiverInfos(String[] packages, int[] userIds) {
final List<ResolveInfo> receivers = new ArrayList<>();
for (int i = 0; i < packages.length; i++) {
for (final int userId : userIds) {
receivers.add(createResolveInfo(packages[i],
UserHandle.getUid(userId, Process.FIRST_APPLICATION_UID + i)));
}
}
return receivers;
}
/**
* Create a new list which filters out item if package name or user id is matched.
* Null package name or user id < 0 will be considered as don't care.
*/
private static List<ResolveInfo> excludeReceivers(List<ResolveInfo> receivers,
String packageName, int userId) {
final List<ResolveInfo> excludedList = new ArrayList<>();
for (final ResolveInfo receiver : receivers) {
if ((packageName != null
&& !packageName.equals(receiver.activityInfo.applicationInfo.packageName))
|| (userId > -1 && userId != UserHandle
.getUserId(receiver.activityInfo.applicationInfo.uid))) {
excludedList.add(receiver);
}
}
return excludedList;
}
private static BroadcastRecord createBroadcastRecord(List<ResolveInfo> receivers, int userId) {
return new BroadcastRecord(
null /* queue */,
new Intent(),
null /* callerApp */,
null /* callerPackage */,
null /* callerFeatureId */,
0 /* callingPid */,
0 /* callingUid */,
false /* callerInstantApp */,
null /* resolvedType */,
null /* requiredPermissions */,
null /* excludedPermissions */,
null /* excludedPackages */,
0 /* appOp */,
null /* options */,
new ArrayList<>(receivers), // Make a copy to not affect the original list.
null /* resultTo */,
0 /* resultCode */,
null /* resultData */,
null /* resultExtras */,
false /* serialized */,
false /* sticky */,
false /* initialSticky */,
userId,
false /* allowBackgroundActivityStarts */,
null /* activityStartsToken */,
false /* timeoutExempt */ );
}
}