blob: d0a656c69f430c6234de3d10cc879a7a31032a08 [file] [log] [blame]
/*
* 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.server.notification;
import static com.android.server.notification.ManagedServices.APPROVAL_BY_COMPONENT;
import static com.android.server.notification.ManagedServices.APPROVAL_BY_PACKAGE;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
import android.os.Build;
import android.os.IBinder;
import android.os.IInterface;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Xml;
import com.android.internal.util.FastXmlSerializer;
import com.android.server.UiServiceTestCase;
import com.google.android.collect.Lists;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;
public class ManagedServicesTest extends UiServiceTestCase {
@Mock
private IPackageManager mIpm;
@Mock
private PackageManager mPm;
@Mock
private UserManager mUm;
@Mock
private ManagedServices.UserProfiles mUserProfiles;
Object mLock = new Object();
UserInfo mZero = new UserInfo(0, "zero", 0);
UserInfo mTen = new UserInfo(10, "ten", 0);
private static final String SETTING = "setting";
private static final String SECONDARY_SETTING = "secondary_setting";
private ArrayMap<Integer, String> mExpectedPrimaryPackages;
private ArrayMap<Integer, String> mExpectedPrimaryComponentNames;
private ArrayMap<Integer, String> mExpectedSecondaryPackages;
private ArrayMap<Integer, String> mExpectedSecondaryComponentNames;
// type : user : list of approved
private ArrayMap<Integer, ArrayMap<Integer, String>> mExpectedPrimary = new ArrayMap<>();
private ArrayMap<Integer, ArrayMap<Integer, String>> mExpectedSecondary = new ArrayMap<>();
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
getContext().setMockPackageManager(mPm);
getContext().addMockSystemService(Context.USER_SERVICE, mUm);
List<UserInfo> users = new ArrayList<>();
users.add(mZero);
users.add(mTen);
users.add(new UserInfo(11, "11", 0));
users.add(new UserInfo(12, "12", 0));
for (UserInfo user : users) {
when(mUm.getUserInfo(eq(user.id))).thenReturn(user);
}
when(mUm.getUsers()).thenReturn(users);
when(mUserProfiles.getCurrentProfileIds()).thenReturn(new int[] {0, 10, 11, 12});
mExpectedPrimaryPackages = new ArrayMap<>();
mExpectedPrimaryPackages.put(0, "this.is.a.package.name:another.package");
mExpectedPrimaryPackages.put(10, "this.is.another.package");
mExpectedPrimaryPackages.put(11, "");
mExpectedPrimaryPackages.put(12, "bananas!");
mExpectedPrimaryComponentNames = new ArrayMap<>();
mExpectedPrimaryComponentNames.put(0, "this.is.a.package.name/Ba:another.package/B1");
mExpectedPrimaryComponentNames.put(10, "this.is.another.package/M1");
mExpectedPrimaryComponentNames.put(11, "");
mExpectedPrimaryComponentNames.put(12, "bananas!/Bananas!");
mExpectedPrimary.put(APPROVAL_BY_PACKAGE, mExpectedPrimaryPackages);
mExpectedPrimary.put(APPROVAL_BY_COMPONENT, mExpectedPrimaryComponentNames);
mExpectedSecondaryComponentNames = new ArrayMap<>();
mExpectedSecondaryComponentNames.put(0, "secondary/component.Name");
mExpectedSecondaryComponentNames.put(10,
"this.is.another.package/with.Component:component/2:package/component2");
mExpectedSecondaryPackages = new ArrayMap<>();
mExpectedSecondaryPackages.put(0, "secondary");
mExpectedSecondaryPackages.put(10,
"this.is.another.package:component:package");
mExpectedSecondary.put(APPROVAL_BY_PACKAGE, mExpectedSecondaryPackages);
mExpectedSecondary.put(APPROVAL_BY_COMPONENT, mExpectedSecondaryComponentNames);
}
@Test
public void testBackupAndRestore_migration() throws Exception {
for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
mIpm, approvalLevel);
for (int userId : mExpectedPrimary.get(approvalLevel).keySet()) {
service.onSettingRestored(
service.getConfig().secureSettingName,
mExpectedPrimary.get(approvalLevel).get(userId),
Build.VERSION_CODES.O, userId);
}
verifyExpectedApprovedEntries(service, true);
for (int userId : mExpectedSecondary.get(approvalLevel).keySet()) {
service.onSettingRestored(service.getConfig().secondarySettingName,
mExpectedSecondary.get(approvalLevel).get(userId), Build.VERSION_CODES.O,
userId);
}
verifyExpectedApprovedEntries(service);
}
}
@Test
public void testBackupAndRestore_migration_preO() throws Exception {
ArrayMap backupPrimaryPackages = new ArrayMap<>();
backupPrimaryPackages.put(0, "backup.0:backup:0a");
backupPrimaryPackages.put(10, "10.backup");
backupPrimaryPackages.put(11, "eleven");
backupPrimaryPackages.put(12, "");
ArrayMap backupPrimaryComponentNames = new ArrayMap<>();
backupPrimaryComponentNames.put(0, "backup.first/whatever:a/b");
backupPrimaryComponentNames.put(10, "again/M1");
backupPrimaryComponentNames.put(11, "orange/youglad:itisnot/banana");
backupPrimaryComponentNames.put(12, "");
ArrayMap<Integer, ArrayMap<Integer, String>> backupPrimary = new ArrayMap<>();
backupPrimary.put(APPROVAL_BY_PACKAGE, backupPrimaryPackages);
backupPrimary.put(APPROVAL_BY_COMPONENT, backupPrimaryComponentNames);
ArrayMap backupSecondaryComponentNames = new ArrayMap<>();
backupSecondaryComponentNames.put(0, "secondary.1/component.Name");
backupSecondaryComponentNames.put(10,
"this.is.another.package.backup/with.Component:component.backup/2");
ArrayMap backupSecondaryPackages = new ArrayMap<>();
backupSecondaryPackages.put(0, "");
backupSecondaryPackages.put(10,
"this.is.another.package.backup:package.backup");
ArrayMap<Integer, ArrayMap<Integer, String>> backupSecondary = new ArrayMap<>();
backupSecondary.put(APPROVAL_BY_PACKAGE, backupSecondaryPackages);
backupSecondary.put(APPROVAL_BY_COMPONENT, backupSecondaryComponentNames);
for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
mIpm, approvalLevel);
// not an expected flow but a way to get data into the settings
for (int userId : mExpectedPrimary.get(approvalLevel).keySet()) {
service.onSettingRestored(
service.getConfig().secureSettingName,
mExpectedPrimary.get(approvalLevel).get(userId),
Build.VERSION_CODES.O, userId);
}
for (int userId : mExpectedSecondary.get(approvalLevel).keySet()) {
service.onSettingRestored(service.getConfig().secondarySettingName,
mExpectedSecondary.get(approvalLevel).get(userId), Build.VERSION_CODES.O,
userId);
}
// actual test
for (int userId : backupPrimary.get(approvalLevel).keySet()) {
service.onSettingRestored(
service.getConfig().secureSettingName,
backupPrimary.get(approvalLevel).get(userId),
Build.VERSION_CODES.N_MR1, userId);
}
verifyExpectedApprovedEntries(service, true);
for (int userId : backupSecondary.get(approvalLevel).keySet()) {
service.onSettingRestored(service.getConfig().secondarySettingName,
backupSecondary.get(approvalLevel).get(userId),
Build.VERSION_CODES.N_MR1, userId);
}
verifyExpectedApprovedEntries(service);
verifyExpectedApprovedEntries(service, backupPrimary.get(approvalLevel));
verifyExpectedApprovedEntries(service, backupSecondary.get(approvalLevel));
}
}
@Test
public void testReadXml_migrationFromSettings() throws Exception {
for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
mIpm, approvalLevel);
// approved services aren't in xml
XmlPullParser parser = Xml.newPullParser();
parser.setInput(new BufferedInputStream(new ByteArrayInputStream(new byte[]{})),
null);
writeExpectedValuesToSettings(approvalLevel);
service.migrateToXml();
verifyExpectedApprovedEntries(service);
}
}
@Test
public void testReadXml() throws Exception {
for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
mIpm, approvalLevel);
loadXml(service);
verifyExpectedApprovedEntries(service);
int[] invalidUsers = new int[] {98, 99};
for (int invalidUser : invalidUsers) {
assertFalse("service type " + service.mApprovalLevel + ":"
+ invalidUser + " is allowed for user " + invalidUser,
service.isPackageOrComponentAllowed(
String.valueOf(invalidUser), invalidUser));
}
}
}
@Test
public void testReadXml_appendsListOfApprovedComponents() throws Exception {
for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
mIpm, approvalLevel);
String preApprovedPackage = "some.random.package";
String preApprovedComponent = "some.random.package/C1";
List<String> packages = new ArrayList<>();
packages.add(preApprovedPackage);
addExpectedServices(service, packages, 0);
service.setPackageOrComponentEnabled(preApprovedComponent, 0, true, true);
loadXml(service);
verifyExpectedApprovedEntries(service);
String verifyValue = (approvalLevel == APPROVAL_BY_COMPONENT)
? preApprovedComponent
: preApprovedPackage;
assertTrue(service.isPackageOrComponentAllowed(verifyValue, 0));
}
}
@Test
public void testWriteXml_trimsMissingServices() throws Exception {
for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
mIpm, approvalLevel);
loadXml(service);
// remove missing
mExpectedPrimaryPackages.put(0, "another.package");
mExpectedPrimaryPackages.remove(12);
mExpectedPrimaryComponentNames.put(0, "another.package/B1");
mExpectedPrimaryComponentNames.remove(12);
mExpectedSecondaryPackages.put(10, "this.is.another.package:component");
mExpectedSecondaryComponentNames.put(
10, "this.is.another.package/with.Component:component/2");
for (UserInfo userInfo : mUm.getUsers()) {
List<String> entriesExpectedToHaveServices = new ArrayList<>();
if (mExpectedPrimary.get(approvalLevel).containsKey(userInfo.id)) {
for (String packageOrComponent :
mExpectedPrimary.get(approvalLevel).get(userInfo.id).split(":")) {
if (!TextUtils.isEmpty(packageOrComponent)) {
entriesExpectedToHaveServices.add(
service.getPackageName(packageOrComponent));
}
}
}
if (mExpectedSecondary.get(approvalLevel).containsKey(userInfo.id)) {
for (String packageOrComponent :
mExpectedSecondary.get(approvalLevel).get(userInfo.id).split(":")) {
if (!TextUtils.isEmpty(packageOrComponent)) {
entriesExpectedToHaveServices.add(
service.getPackageName(packageOrComponent));
}
}
}
addExpectedServices(service, entriesExpectedToHaveServices, userInfo.id);
}
XmlSerializer serializer = new FastXmlSerializer();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
serializer.startDocument(null, true);
service.writeXml(serializer, true);
serializer.endDocument();
serializer.flush();
XmlPullParser parser = Xml.newPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(baos.toByteArray())), null);
parser.nextTag();
service.readXml(parser, null);
verifyExpectedApprovedEntries(service);
assertFalse(service.isPackageOrComponentAllowed("this.is.a.package.name", 0));
assertFalse(service.isPackageOrComponentAllowed("bananas!", 12));
assertFalse(service.isPackageOrComponentAllowed("package/component2", 10));
}
}
@Test
public void testWriteXml_writesSetting() throws Exception {
for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
mIpm, approvalLevel);
loadXml(service);
XmlSerializer serializer = new FastXmlSerializer();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
serializer.startDocument(null, true);
service.writeXml(serializer, false);
serializer.endDocument();
serializer.flush();
for (int userId : mUserProfiles.getCurrentProfileIds()) {
List<String> expected =
stringToList(mExpectedPrimary.get(approvalLevel).get(userId));
List<String> actual = stringToList(Settings.Secure.getStringForUser(
getContext().getContentResolver(),
service.getConfig().secureSettingName, userId));
assertContentsInAnyOrder(actual, expected);
}
}
}
@Test
public void rebindServices_onlyBindsExactMatchesIfComponent() throws Exception {
// If the primary and secondary lists contain component names, only those components within
// the package should be matched
ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
mIpm,
ManagedServices.APPROVAL_BY_COMPONENT);
List<String> packages = new ArrayList<>();
packages.add("package");
packages.add("anotherPackage");
addExpectedServices(service, packages, 0);
// only 2 components are approved per package
mExpectedPrimaryComponentNames.clear();
mExpectedPrimaryComponentNames.put(0, "package/C1:package/C2");
mExpectedSecondaryComponentNames.clear();
mExpectedSecondaryComponentNames.put(0, "anotherPackage/C1:anotherPackage/C2");
loadXml(service);
// verify the 2 components per package are enabled (bound)
verifyExpectedBoundEntries(service, true);
verifyExpectedBoundEntries(service, false);
// verify the last component per package is not enabled/we don't try to bind to it
for (String pkg : packages) {
ComponentName unapprovedAdditionalComponent =
ComponentName.unflattenFromString(pkg + "/C3");
assertFalse(
service.isComponentEnabledForCurrentProfiles(
unapprovedAdditionalComponent));
verify(mIpm, never()).getServiceInfo(
eq(unapprovedAdditionalComponent), anyInt(), anyInt());
}
}
@Test
public void rebindServices_bindsEverythingInAPackage() throws Exception {
// If the primary and secondary lists contain packages, all components within those packages
// should be bound
ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm,
APPROVAL_BY_PACKAGE);
List<String> packages = new ArrayList<>();
packages.add("package");
packages.add("packagea");
addExpectedServices(service, packages, 0);
// 2 approved packages
mExpectedPrimaryPackages.clear();
mExpectedPrimaryPackages.put(0, "package");
mExpectedSecondaryPackages.clear();
mExpectedSecondaryPackages.put(0, "packagea");
loadXml(service);
// verify the 3 components per package are enabled (bound)
verifyExpectedBoundEntries(service, true);
verifyExpectedBoundEntries(service, false);
}
@Test
public void testPackageUninstall_packageNoLongerInApprovedList() throws Exception {
for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
mIpm, approvalLevel);
writeExpectedValuesToSettings(approvalLevel);
service.migrateToXml();
mExpectedPrimaryPackages.put(0, "another.package");
mExpectedPrimaryComponentNames.put(0, "another.package/B1");
service.onPackagesChanged(true, new String[]{"this.is.a.package.name"}, new int[]{103});
verifyExpectedApprovedEntries(service);
}
}
@Test
public void testPackageUninstall_componentNoLongerInApprovedList() throws Exception {
for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
mIpm, approvalLevel);
writeExpectedValuesToSettings(approvalLevel);
service.migrateToXml();
mExpectedSecondaryComponentNames.put(10, "component/2");
mExpectedSecondaryPackages.put(10, "component");
service.onPackagesChanged(true, new String[]{"this.is.another.package"}, new int[]{
UserHandle.PER_USER_RANGE + 1});
verifyExpectedApprovedEntries(service);
}
}
@Test
public void testSetPackageOrComponentEnabled() throws Exception {
for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
mIpm, approvalLevel);
ArrayMap<Integer, ArrayList<String>> expectedEnabled = new ArrayMap<>();
expectedEnabled.put(0,
Lists.newArrayList(new String[]{"package/Comp", "package/C2", "again/M4"}));
expectedEnabled.put(10,
Lists.newArrayList(new String[]{"user10package/B", "user10/Component",
"user10package1/K", "user10.3/Component", "user10package2/L",
"user10.4/Component"}));
for (int userId : expectedEnabled.keySet()) {
ArrayList<String> expectedForUser = expectedEnabled.get(userId);
for (int i = 0; i < expectedForUser.size(); i++) {
boolean primary = i % 2 == 0;
service.setPackageOrComponentEnabled(expectedForUser.get(i), userId, primary,
true);
}
}
// verify everything added is approved
for (int userId : expectedEnabled.keySet()) {
ArrayList<String> expectedForUser = expectedEnabled.get(userId);
for (int i = 0; i < expectedForUser.size(); i++) {
String verifyValue = (approvalLevel == APPROVAL_BY_COMPONENT)
? expectedForUser.get(i)
: service.getPackageName(expectedForUser.get(i));
assertTrue("Not allowed: user: " + userId + " entry: " + verifyValue
+ " for approval level " + approvalLevel,
service.isPackageOrComponentAllowed(verifyValue, userId));
}
}
ArrayMap<Integer, ArrayList<String>> expectedNoAccess = new ArrayMap<>();
for (int userId : expectedEnabled.keySet()) {
ArrayList<String> expectedForUser = expectedEnabled.get(userId);
for (int i = expectedForUser.size() - 1; i >= 0; i--) {
ArrayList<String> removed = new ArrayList<>();
if (i % 3 == 0) {
String revokeAccessFor = expectedForUser.remove(i);
removed.add(revokeAccessFor);
service.setPackageOrComponentEnabled(
revokeAccessFor, userId, i % 2 == 0, false);
}
expectedNoAccess.put(userId, removed);
}
}
// verify everything still there is approved
for (int userId : expectedEnabled.keySet()) {
ArrayList<String> expectedForUser = expectedEnabled.get(userId);
for (int i = 0; i < expectedForUser.size(); i++) {
String verifyValue = (approvalLevel == APPROVAL_BY_COMPONENT)
? expectedForUser.get(i)
: service.getPackageName(expectedForUser.get(i));
assertTrue("Not allowed: user: " + userId + " entry: " + verifyValue,
service.isPackageOrComponentAllowed(verifyValue, userId));
}
}
// verify everything removed isn't
for (int userId : expectedNoAccess.keySet()) {
ArrayList<String> notExpectedForUser = expectedNoAccess.get(userId);
for (int i = 0; i < notExpectedForUser.size(); i++) {
assertFalse(
"Is allowed: user: " + userId + " entry: " + notExpectedForUser.get(i),
service.isPackageOrComponentAllowed(notExpectedForUser.get(i), userId));
}
}
}
}
@Test
public void testGetAllowedPackages() throws Exception {
for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
mIpm, approvalLevel);
loadXml(service);
List<String> allowedPackagesForUser0 = new ArrayList<>();
allowedPackagesForUser0.add("this.is.a.package.name");
allowedPackagesForUser0.add("another.package");
allowedPackagesForUser0.add("secondary");
List<String> actual = service.getAllowedPackages(0);
assertEquals(3, actual.size());
for (String pkg : allowedPackagesForUser0) {
assertTrue(actual.contains(pkg));
}
List<String> allowedPackagesForUser10 = new ArrayList<>();
allowedPackagesForUser10.add("this.is.another.package");
allowedPackagesForUser10.add("package");
allowedPackagesForUser10.add("this.is.another.package");
allowedPackagesForUser10.add("component");
actual = service.getAllowedPackages(10);
assertEquals(4, actual.size());
for (String pkg : allowedPackagesForUser10) {
assertTrue(actual.contains(pkg));
}
}
}
@Test
public void testGetAllowedComponents() throws Exception {
ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm,
APPROVAL_BY_COMPONENT);
loadXml(service);
List<ComponentName> expected = new ArrayList<>();
expected.add(ComponentName.unflattenFromString("this.is.another.package/M1"));
expected.add(ComponentName.unflattenFromString("this.is.another.package/with.Component"));
expected.add(ComponentName.unflattenFromString("component/2"));
expected.add(ComponentName.unflattenFromString("package/component2"));
List<ComponentName> actual = service.getAllowedComponents(10);
assertContentsInAnyOrder(expected, actual);
assertEquals(expected.size(), actual.size());
for (ComponentName cn : expected) {
assertTrue("Actual missing " + cn, actual.contains(cn));
}
for (ComponentName cn : actual) {
assertTrue("Actual contains extra " + cn, expected.contains(cn));
}
}
@Test
public void testGetAllowedComponents_approvalByPackage() throws Exception {
ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm,
APPROVAL_BY_PACKAGE);
loadXml(service);
assertEquals(0, service.getAllowedComponents(10).size());
}
@Test
public void testOnUserRemoved() throws Exception {
for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
mIpm, approvalLevel);
loadXml(service);
ArrayMap<Integer, String> verifyMap = mExpectedPrimary.get(service.mApprovalLevel);
String user0 = verifyMap.remove(0);
verifyMap = mExpectedSecondary.get(service.mApprovalLevel);
user0 = user0 + ":" + verifyMap.remove(0);
service.onUserRemoved(0);
for (String verifyValue : user0.split(":")) {
if (!TextUtils.isEmpty(verifyValue)) {
assertFalse("service type " + service.mApprovalLevel + ":" + verifyValue
+ " is still allowed",
service.isPackageOrComponentAllowed(verifyValue, 0));
}
}
verifyExpectedApprovedEntries(service);
}
}
private void loadXml(ManagedServices service) throws Exception {
final StringBuffer xml = new StringBuffer();
xml.append("<" + service.getConfig().xmlTag + ">\n");
for (int userId : mExpectedPrimary.get(service.mApprovalLevel).keySet()) {
xml.append(getXmlEntry(
mExpectedPrimary.get(service.mApprovalLevel).get(userId), userId, true));
}
for (int userId : mExpectedSecondary.get(service.mApprovalLevel).keySet()) {
xml.append(getXmlEntry(
mExpectedSecondary.get(service.mApprovalLevel).get(userId), userId, false));
}
xml.append("<" + ManagedServices.TAG_MANAGED_SERVICES + " "
+ ManagedServices.ATT_USER_ID + "=\"99\" "
+ ManagedServices.ATT_IS_PRIMARY + "=\"true\" "
+ ManagedServices.ATT_APPROVED_LIST + "=\"99\" />\n");
xml.append("<" + ManagedServices.TAG_MANAGED_SERVICES + " "
+ ManagedServices.ATT_USER_ID + "=\"98\" "
+ ManagedServices.ATT_IS_PRIMARY + "=\"false\" "
+ ManagedServices.ATT_APPROVED_LIST + "=\"98\" />\n");
xml.append("</" + service.getConfig().xmlTag + ">");
XmlPullParser parser = Xml.newPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(xml.toString().getBytes())), null);
parser.nextTag();
service.readXml(parser, null);
}
private void addExpectedServices(final ManagedServices service, final List<String> packages,
int userId) {
when(mPm.queryIntentServicesAsUser(any(), anyInt(), eq(userId))).
thenAnswer(new Answer<List<ResolveInfo>>() {
@Override
public List<ResolveInfo> answer(InvocationOnMock invocationOnMock)
throws Throwable {
Object[] args = invocationOnMock.getArguments();
Intent invocationIntent = (Intent) args[0];
if (invocationIntent != null) {
if (invocationIntent.getAction().equals(
service.getConfig().serviceInterface)
&& packages.contains(invocationIntent.getPackage())) {
List<ResolveInfo> dummyServices = new ArrayList<>();
for (int i = 1; i <= 3; i ++) {
ResolveInfo resolveInfo = new ResolveInfo();
ServiceInfo serviceInfo = new ServiceInfo();
serviceInfo.packageName = invocationIntent.getPackage();
serviceInfo.name = "C"+i;
serviceInfo.permission = service.getConfig().bindPermission;
resolveInfo.serviceInfo = serviceInfo;
dummyServices.add(resolveInfo);
}
return dummyServices;
}
}
return new ArrayList<>();
}
});
}
private List<String> stringToList(String list) {
if (list == null) {
list = "";
}
return new ArrayList<>(Lists.newArrayList(list.split(
ManagedServices.ENABLED_SERVICES_SEPARATOR)));
}
private void assertContentsInAnyOrder(List<?> expected, List<?> actual) {
assertEquals(expected.size(), actual.size());
for (Object o : expected) {
assertTrue("Actual missing " + o, actual.contains(o));
}
for (Object o : actual) {
assertTrue("Actual contains extra " + o, expected.contains(o));
}
}
private void verifyExpectedBoundEntries(ManagedServices service, boolean primary)
throws Exception {
ArrayMap<Integer, String> verifyMap = primary ? mExpectedPrimary.get(service.mApprovalLevel)
: mExpectedSecondary.get(service.mApprovalLevel);
for (int userId : verifyMap.keySet()) {
for (String packageOrComponent : verifyMap.get(userId).split(":")) {
if (!TextUtils.isEmpty(packageOrComponent)) {
if (service.mApprovalLevel == APPROVAL_BY_PACKAGE) {
assertTrue(packageOrComponent,
service.isComponentEnabledForPackage(packageOrComponent));
for (int i = 1; i <= 3; i ++) {
ComponentName componentName = ComponentName.unflattenFromString(
packageOrComponent +"/C" + i);
assertTrue(service.isComponentEnabledForCurrentProfiles(
componentName));
verify(mIpm, times(1)).getServiceInfo(
eq(componentName), anyInt(), anyInt());
}
} else {
ComponentName componentName =
ComponentName.unflattenFromString(packageOrComponent);
assertTrue(service.isComponentEnabledForCurrentProfiles(componentName));
verify(mIpm, times(1)).getServiceInfo(
eq(componentName), anyInt(), anyInt());
}
}
}
}
}
private void verifyExpectedApprovedEntries(ManagedServices service) {
verifyExpectedApprovedEntries(service, true);
verifyExpectedApprovedEntries(service, false);
}
private void verifyExpectedApprovedEntries(ManagedServices service, boolean primary) {
ArrayMap<Integer, String> verifyMap = primary
? mExpectedPrimary.get(service.mApprovalLevel)
: mExpectedSecondary.get(service.mApprovalLevel);
verifyExpectedApprovedEntries(service, verifyMap);
}
private void verifyExpectedApprovedEntries(ManagedServices service,
ArrayMap<Integer, String> verifyMap) {
for (int userId : verifyMap.keySet()) {
for (String verifyValue : verifyMap.get(userId).split(":")) {
if (!TextUtils.isEmpty(verifyValue)) {
assertTrue("service type " + service.mApprovalLevel + ":"
+ verifyValue + " is not allowed for user " + userId,
service.isPackageOrComponentAllowed(verifyValue, userId));
}
}
}
}
private void writeExpectedValuesToSettings(int approvalLevel) {
for (int userId : mExpectedPrimary.get(approvalLevel).keySet()) {
Settings.Secure.putStringForUser(getContext().getContentResolver(), SETTING,
mExpectedPrimary.get(approvalLevel).get(userId), userId);
}
for (int userId : mExpectedSecondary.get(approvalLevel).keySet()) {
Settings.Secure.putStringForUser(getContext().getContentResolver(), SECONDARY_SETTING,
mExpectedSecondary.get(approvalLevel).get(userId), userId);
}
}
private String getXmlEntry(String approved, int userId, boolean isPrimary) {
return "<" + ManagedServices.TAG_MANAGED_SERVICES + " "
+ ManagedServices.ATT_USER_ID + "=\"" + userId +"\" "
+ ManagedServices.ATT_IS_PRIMARY + "=\"" + isPrimary +"\" "
+ ManagedServices.ATT_APPROVED_LIST + "=\"" + approved +"\" "
+ "/>\n";
}
class TestManagedServices extends ManagedServices {
public TestManagedServices(Context context, Object mutex, UserProfiles userProfiles,
IPackageManager pm, int approvedServiceType) {
super(context, mutex, userProfiles, pm);
mApprovalLevel = approvedServiceType;
}
@Override
protected Config getConfig() {
final Config c = new Config();
c.xmlTag = "test";
c.secureSettingName = SETTING;
c.secondarySettingName = SECONDARY_SETTING;
c.bindPermission = "permission";
c.serviceInterface = "serviceInterface";
return c;
}
@Override
protected IInterface asInterface(IBinder binder) {
return null;
}
@Override
protected boolean checkType(IInterface service) {
return false;
}
@Override
protected void onServiceAdded(ManagedServiceInfo info) {
}
}
}