Merge "Auto enable new system trust agents" into tm-qpr-dev

This commit is contained in:
Jason Sun
2022-09-20 19:48:17 +00:00
committed by Android (Google) Code Review
7 changed files with 530 additions and 27 deletions

View File

@@ -7426,6 +7426,13 @@ public final class Settings {
public static final String TRUST_AGENTS_INITIALIZED =
"trust_agents_initialized";
/**
* Set to 1 by the system after the list of known trust agents have been initialized.
* @hide
*/
public static final String KNOWN_TRUST_AGENTS_INITIALIZED =
"known_trust_agents_initialized";
/**
* The Logging ID (a unique 64-bit value) as a hex string.
* Used as a pseudonymous identifier for logging.

View File

@@ -39,7 +39,6 @@ import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
@@ -47,7 +46,6 @@ import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
import android.provider.Settings;
import android.text.TextUtils;
@@ -175,6 +173,7 @@ public class LockPatternUtils {
private static final String LOCK_SCREEN_DEVICE_OWNER_INFO = "lockscreen.device_owner_info";
private static final String ENABLED_TRUST_AGENTS = "lockscreen.enabledtrustagents";
private static final String KNOWN_TRUST_AGENTS = "lockscreen.knowntrustagents";
private static final String IS_TRUST_USUALLY_MANAGED = "lockscreen.istrustusuallymanaged";
public static final String PROFILE_KEY_NAME_ENCRYPT = "profile_key_name_encrypt_";
@@ -1106,31 +1105,50 @@ public class LockPatternUtils {
return getString(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, userId) != null;
}
/** Updates the list of enabled trust agent in LockSettings storage for the given user. */
public void setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents, int userId) {
setString(ENABLED_TRUST_AGENTS, serializeTrustAgents(activeTrustAgents), userId);
getTrustManager().reportEnabledTrustAgentsChanged(userId);
}
/** Returns the list of enabled trust agent in LockSettings storage for the given user. */
public List<ComponentName> getEnabledTrustAgents(int userId) {
return deserializeTrustAgents(getString(ENABLED_TRUST_AGENTS, userId));
}
/** Updates the list of known trust agent in LockSettings storage for the given user. */
public void setKnownTrustAgents(Collection<ComponentName> knownTrustAgents, int userId) {
setString(KNOWN_TRUST_AGENTS, serializeTrustAgents(knownTrustAgents), userId);
}
/** Returns the list of known trust agent in LockSettings storage for the given user. */
public List<ComponentName> getKnownTrustAgents(int userId) {
return deserializeTrustAgents(getString(KNOWN_TRUST_AGENTS, userId));
}
private String serializeTrustAgents(Collection<ComponentName> trustAgents) {
StringBuilder sb = new StringBuilder();
for (ComponentName cn : activeTrustAgents) {
for (ComponentName cn : trustAgents) {
if (sb.length() > 0) {
sb.append(',');
}
sb.append(cn.flattenToShortString());
}
setString(ENABLED_TRUST_AGENTS, sb.toString(), userId);
getTrustManager().reportEnabledTrustAgentsChanged(userId);
return sb.toString();
}
public List<ComponentName> getEnabledTrustAgents(int userId) {
String serialized = getString(ENABLED_TRUST_AGENTS, userId);
if (TextUtils.isEmpty(serialized)) {
return new ArrayList<ComponentName>();
private List<ComponentName> deserializeTrustAgents(String serializedTrustAgents) {
if (TextUtils.isEmpty(serializedTrustAgents)) {
return new ArrayList<>();
}
String[] split = serialized.split(",");
ArrayList<ComponentName> activeTrustAgents = new ArrayList<ComponentName>(split.length);
String[] split = serializedTrustAgents.split(",");
ArrayList<ComponentName> trustAgents = new ArrayList<>(split.length);
for (String s : split) {
if (!TextUtils.isEmpty(s)) {
activeTrustAgents.add(ComponentName.unflattenFromString(s));
trustAgents.add(ComponentName.unflattenFromString(s));
}
}
return activeTrustAgents;
return trustAgents;
}
/**

View File

@@ -19,14 +19,15 @@ package com.android.internal.util;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_MANAGED;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
import static org.junit.Assert.assertEquals;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -51,8 +52,11 @@ import com.android.internal.widget.IWeakEscrowTokenActivatedListener;
import com.android.internal.widget.IWeakEscrowTokenRemovedListener;
import com.android.internal.widget.LockPatternUtils;
import com.google.android.collect.Lists;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import java.nio.charset.StandardCharsets;
@@ -172,13 +176,61 @@ public class LockPatternUtilsTest {
}
@Test
public void testGetEnabledTrustAgentsNotNull() throws RemoteException {
public void testSetEnabledTrustAgents() throws RemoteException {
int testUserId = 10;
ILockSettings ils = createTestLockSettings();
when(ils.getString(anyString(), any(), anyInt())).thenReturn("");
ArgumentCaptor<String> valueCaptor = ArgumentCaptor.forClass(String.class);
doNothing().when(ils).setString(anyString(), valueCaptor.capture(), anyInt());
List<ComponentName> enabledTrustAgents = Lists.newArrayList(
ComponentName.unflattenFromString("com.android/.TrustAgent"),
ComponentName.unflattenFromString("com.test/.TestAgent"));
mLockPatternUtils.setEnabledTrustAgents(enabledTrustAgents, testUserId);
assertThat(valueCaptor.getValue()).isEqualTo("com.android/.TrustAgent,com.test/.TestAgent");
}
@Test
public void testGetEnabledTrustAgents() throws RemoteException {
int testUserId = 10;
ILockSettings ils = createTestLockSettings();
when(ils.getString(anyString(), any(), anyInt())).thenReturn(
"com.android/.TrustAgent,com.test/.TestAgent");
List<ComponentName> trustAgents = mLockPatternUtils.getEnabledTrustAgents(testUserId);
assertNotNull(trustAgents);
assertEquals(0, trustAgents.size());
assertThat(trustAgents).containsExactly(
ComponentName.unflattenFromString("com.android/.TrustAgent"),
ComponentName.unflattenFromString("com.test/.TestAgent"));
}
@Test
public void testSetKnownTrustAgents() throws RemoteException {
int testUserId = 10;
ILockSettings ils = createTestLockSettings();
ArgumentCaptor<String> valueCaptor = ArgumentCaptor.forClass(String.class);
doNothing().when(ils).setString(anyString(), valueCaptor.capture(), anyInt());
List<ComponentName> knownTrustAgents = Lists.newArrayList(
ComponentName.unflattenFromString("com.android/.TrustAgent"),
ComponentName.unflattenFromString("com.test/.TestAgent"));
mLockPatternUtils.setKnownTrustAgents(knownTrustAgents, testUserId);
assertThat(valueCaptor.getValue()).isEqualTo("com.android/.TrustAgent,com.test/.TestAgent");
}
@Test
public void testGetKnownTrustAgents() throws RemoteException {
int testUserId = 10;
ILockSettings ils = createTestLockSettings();
when(ils.getString(anyString(), any(), anyInt())).thenReturn(
"com.android/.TrustAgent,com.test/.TestAgent");
List<ComponentName> trustAgents = mLockPatternUtils.getKnownTrustAgents(testUserId);
assertThat(trustAgents).containsExactly(
ComponentName.unflattenFromString("com.android/.TrustAgent"),
ComponentName.unflattenFromString("com.test/.TestAgent"));
}
private ILockSettings createTestLockSettings() {

View File

@@ -780,6 +780,7 @@ public class SettingsBackupTest {
Settings.Secure.SMS_DEFAULT_APPLICATION,
Settings.Secure.SPELL_CHECKER_ENABLED, // Intentionally removed in Q
Settings.Secure.TRUST_AGENTS_INITIALIZED,
Settings.Secure.KNOWN_TRUST_AGENTS_INITIALIZED,
Settings.Secure.TV_APP_USES_NON_SYSTEM_INPUTS,
Settings.Secure.TV_INPUT_CUSTOM_LABELS,
Settings.Secure.TV_INPUT_HIDDEN_INPUTS,

View File

@@ -93,6 +93,7 @@ import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -254,6 +255,7 @@ public class TrustManagerService extends SystemService {
return;
}
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
checkNewAgents();
mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
mReceiver.register(mContext);
mLockPatternUtils.registerStrongAuthTracker(mStrongAuthTracker);
@@ -262,7 +264,7 @@ public class TrustManagerService extends SystemService {
refreshAgentList(UserHandle.USER_ALL);
refreshDeviceLockedForUser(UserHandle.USER_ALL);
} else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
maybeEnableFactoryTrustAgents(mLockPatternUtils, UserHandle.USER_SYSTEM);
maybeEnableFactoryTrustAgents(UserHandle.USER_SYSTEM);
}
}
@@ -1083,7 +1085,7 @@ public class TrustManagerService extends SystemService {
return new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name);
}
private void maybeEnableFactoryTrustAgents(LockPatternUtils utils, int userId) {
private void maybeEnableFactoryTrustAgents(int userId) {
if (0 != Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.TRUST_AGENTS_INITIALIZED, 0, userId)) {
return;
@@ -1100,8 +1102,7 @@ public class TrustManagerService extends SystemService {
} else { // A default agent is not set; perform regular trust agent discovery
for (ResolveInfo resolveInfo : resolveInfos) {
ComponentName componentName = getComponentName(resolveInfo);
int applicationInfoFlags = resolveInfo.serviceInfo.applicationInfo.flags;
if ((applicationInfoFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
if (!isSystemTrustAgent(resolveInfo)) {
Log.i(TAG, "Leaving agent " + componentName + " disabled because package "
+ "is not a system package.");
continue;
@@ -1110,13 +1111,88 @@ public class TrustManagerService extends SystemService {
}
}
List<ComponentName> previouslyEnabledAgents = utils.getEnabledTrustAgents(userId);
discoveredAgents.addAll(previouslyEnabledAgents);
utils.setEnabledTrustAgents(discoveredAgents, userId);
enableNewAgents(discoveredAgents, userId);
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.TRUST_AGENTS_INITIALIZED, 1, userId);
}
private void checkNewAgents() {
for (UserInfo userInfo : mUserManager.getAliveUsers()) {
checkNewAgentsForUser(userInfo.id);
}
}
/**
* Checks for any new trust agents that become available after the first boot, add them to the
* list of known agents, and enable them if they should be enabled by default.
*/
private void checkNewAgentsForUser(int userId) {
// When KNOWN_TRUST_AGENTS_INITIALIZED is not set, only update the known agent list but do
// not enable any agent.
// These agents will be enabled by #maybeEnableFactoryTrustAgents if this is the first time
// that this device boots and TRUST_AGENTS_INITIALIZED is not already set.
// Otherwise, these agents may have been manually disabled by the user, and we should not
// re-enable them.
if (0 == Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.KNOWN_TRUST_AGENTS_INITIALIZED, 0, userId)) {
initializeKnownAgents(userId);
return;
}
List<ComponentName> knownAgents = mLockPatternUtils.getKnownTrustAgents(userId);
List<ResolveInfo> agentInfoList = resolveAllowedTrustAgents(mContext.getPackageManager(),
userId);
ArraySet<ComponentName> newAgents = new ArraySet<>(agentInfoList.size());
ArraySet<ComponentName> newSystemAgents = new ArraySet<>(agentInfoList.size());
for (ResolveInfo agentInfo : agentInfoList) {
ComponentName agentComponentName = getComponentName(agentInfo);
if (knownAgents.contains(agentComponentName)) {
continue;
}
newAgents.add(agentComponentName);
if (isSystemTrustAgent(agentInfo)) {
newSystemAgents.add(agentComponentName);
}
}
if (newAgents.isEmpty()) {
return;
}
ArraySet<ComponentName> updatedKnowAgents = new ArraySet<>(knownAgents);
updatedKnowAgents.addAll(newAgents);
mLockPatternUtils.setKnownTrustAgents(updatedKnowAgents, userId);
// Do not auto enable new trust agents when the default agent is set
boolean hasDefaultAgent = getDefaultFactoryTrustAgent(mContext) != null;
if (!hasDefaultAgent) {
enableNewAgents(newSystemAgents, userId);
}
}
private void enableNewAgents(Collection<ComponentName> agents, int userId) {
if (agents.isEmpty()) {
return;
}
ArraySet<ComponentName> agentsToEnable = new ArraySet<>(agents);
agentsToEnable.addAll(mLockPatternUtils.getEnabledTrustAgents(userId));
mLockPatternUtils.setEnabledTrustAgents(agentsToEnable, userId);
}
private void initializeKnownAgents(int userId) {
List<ResolveInfo> agentInfoList = resolveAllowedTrustAgents(mContext.getPackageManager(),
userId);
ArraySet<ComponentName> agentComponentNames = new ArraySet<>(agentInfoList.size());
for (ResolveInfo agentInfo : agentInfoList) {
agentComponentNames.add(getComponentName(agentInfo));
}
mLockPatternUtils.setKnownTrustAgents(agentComponentNames, userId);
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.KNOWN_TRUST_AGENTS_INITIALIZED, 1, userId);
}
/**
* Returns the {@link ComponentName} for the default trust agent, or {@code null} if there
* is no trust agent set.
@@ -1152,6 +1228,10 @@ public class TrustManagerService extends SystemService {
return allowedAgents;
}
private static boolean isSystemTrustAgent(ResolveInfo agentInfo) {
return (agentInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
}
// Agent dispatch and aggregation
private boolean aggregateIsTrusted(int userId) {
@@ -1825,8 +1905,14 @@ public class TrustManagerService extends SystemService {
refreshAgentList(UserHandle.USER_ALL);
}
@Override
public void onPackageAdded(String packageName, int uid) {
checkNewAgentsForUser(UserHandle.getUserId(uid));
}
@Override
public boolean onPackageChanged(String packageName, int uid, String[] components) {
checkNewAgentsForUser(UserHandle.getUserId(uid));
// We're interested in all changes, even if just some components get enabled / disabled.
return true;
}
@@ -1861,7 +1947,7 @@ public class TrustManagerService extends SystemService {
action)) {
int userId = getUserId(intent);
if (userId > 0) {
maybeEnableFactoryTrustAgents(mLockPatternUtils, userId);
maybeEnableFactoryTrustAgents(userId);
}
} else if (Intent.ACTION_USER_REMOVED.equals(action)) {
int userId = getUserId(intent);

View File

@@ -34,10 +34,15 @@
<uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
<uses-permission android:name="android.permission.MANAGE_GAME_ACTIVITY" />
<uses-permission android:name="android.permission.SET_ALWAYS_FINISH" />
<uses-permission android:name="android.permission.MANAGE_USERS" />
<uses-permission android:name="android.permission.USE_BIOMETRIC_INTERNAL" />
<!-- needed by MasterClearReceiverTest to display a system dialog -->
<uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"/>
<!-- needed by TrustManagerServiceTest to access LockSettings' secure storage -->
<uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
<application android:testOnly="true"
android:debuggable="true">
<uses-library android:name="android.test.runner" />

View File

@@ -0,0 +1,334 @@
/*
* Copyright (C) 2022 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.trust;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.argThat;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static com.google.common.truth.Truth.assertThat;
import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.net.Uri;
import android.os.Handler;
import android.os.UserHandle;
import android.os.test.TestLooper;
import android.provider.Settings;
import android.service.trust.TrustAgentService;
import android.testing.TestableContext;
import androidx.test.core.app.ApplicationProvider;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.SystemServiceManager;
import com.google.android.collect.Lists;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import java.util.ArrayList;
import java.util.Collections;
public class TrustManagerServiceTest {
@Rule
public MockitoRule mMockitoRule = MockitoJUnit.rule();
@Rule
public final MockContext mMockContext = new MockContext(
ApplicationProvider.getApplicationContext());
private static final String URI_SCHEME_PACKAGE = "package";
private static final int TEST_USER_ID = UserHandle.USER_SYSTEM;
private final TestLooper mLooper = new TestLooper();
private final ArrayList<ResolveInfo> mTrustAgentResolveInfoList = new ArrayList<>();
private final LockPatternUtils mLockPatternUtils = new LockPatternUtils(mMockContext);
private final TrustManagerService mService = new TrustManagerService(mMockContext);
@Mock
private PackageManager mPackageManagerMock;
@Before
public void setUp() {
resetTrustAgentLockSettings();
LocalServices.addService(SystemServiceManager.class, mock(SystemServiceManager.class));
ArgumentMatcher<Intent> trustAgentIntentMatcher = new ArgumentMatcher<Intent>() {
@Override
public boolean matches(Intent argument) {
return TrustAgentService.SERVICE_INTERFACE.equals(argument.getAction());
}
};
when(mPackageManagerMock.queryIntentServicesAsUser(argThat(trustAgentIntentMatcher),
anyInt(), anyInt())).thenReturn(mTrustAgentResolveInfoList);
when(mPackageManagerMock.checkPermission(any(), any())).thenReturn(
PackageManager.PERMISSION_GRANTED);
mMockContext.setMockPackageManager(mPackageManagerMock);
}
@After
public void tearDown() {
resetTrustAgentLockSettings();
LocalServices.removeServiceForTest(SystemServiceManager.class);
}
@Test
public void firstBootCompleted_systemTrustAgentsEnabled() {
ComponentName systemTrustAgent1 = ComponentName.unflattenFromString(
"com.android/.SystemTrustAgent");
ComponentName systemTrustAgent2 = ComponentName.unflattenFromString(
"com.android/.AnotherSystemTrustAgent");
ComponentName userTrustAgent1 = ComponentName.unflattenFromString(
"com.user/.UserTrustAgent");
ComponentName userTrustAgent2 = ComponentName.unflattenFromString(
"com.user/.AnotherUserTrustAgent");
addTrustAgent(systemTrustAgent1, /* isSystemApp= */ true);
addTrustAgent(systemTrustAgent2, /* isSystemApp= */ true);
addTrustAgent(userTrustAgent1, /* isSystemApp= */ false);
addTrustAgent(userTrustAgent2, /* isSystemApp= */ false);
bootService();
assertThat(mLockPatternUtils.getEnabledTrustAgents(TEST_USER_ID)).containsExactly(
systemTrustAgent1, systemTrustAgent2);
assertThat(mLockPatternUtils.getKnownTrustAgents(TEST_USER_ID)).containsExactly(
systemTrustAgent1, systemTrustAgent2, userTrustAgent1, userTrustAgent2);
}
@Test
public void firstBootCompleted_defaultTrustAgentEnabled() {
ComponentName systemTrustAgent = ComponentName.unflattenFromString(
"com.android/.SystemTrustAgent");
ComponentName defaultTrustAgent = ComponentName.unflattenFromString(
"com.user/.DefaultTrustAgent");
addTrustAgent(systemTrustAgent, /* isSystemApp= */ true);
addTrustAgent(defaultTrustAgent, /* isSystemApp= */ false);
mMockContext.getOrCreateTestableResources().addOverride(
com.android.internal.R.string.config_defaultTrustAgent,
defaultTrustAgent.flattenToString());
bootService();
assertThat(mLockPatternUtils.getEnabledTrustAgents(TEST_USER_ID)).containsExactly(
defaultTrustAgent);
assertThat(mLockPatternUtils.getKnownTrustAgents(TEST_USER_ID)).containsExactly(
systemTrustAgent, defaultTrustAgent);
}
@Test
public void serviceBooted_knownAgentsNotSet_enabledAgentsNotUpdated() {
ComponentName trustAgent1 = ComponentName.unflattenFromString(
"com.android/.SystemTrustAgent");
ComponentName trustAgent2 = ComponentName.unflattenFromString(
"com.android/.AnotherSystemTrustAgent");
initializeEnabledAgents(trustAgent1);
addTrustAgent(trustAgent1, /* isSystemApp= */ true);
addTrustAgent(trustAgent2, /* isSystemApp= */ true);
bootService();
assertThat(mLockPatternUtils.getEnabledTrustAgents(TEST_USER_ID)).containsExactly(
trustAgent1);
assertThat(mLockPatternUtils.getKnownTrustAgents(TEST_USER_ID)).containsExactly(
trustAgent1, trustAgent2);
}
@Test
public void serviceBooted_knownAgentsSet_enabledAgentsUpdated() {
ComponentName trustAgent1 = ComponentName.unflattenFromString(
"com.android/.SystemTrustAgent");
ComponentName trustAgent2 = ComponentName.unflattenFromString(
"com.android/.AnotherSystemTrustAgent");
initializeEnabledAgents(trustAgent1);
initializeKnownAgents(trustAgent1);
addTrustAgent(trustAgent1, /* isSystemApp= */ true);
addTrustAgent(trustAgent2, /* isSystemApp= */ true);
bootService();
assertThat(mLockPatternUtils.getEnabledTrustAgents(TEST_USER_ID)).containsExactly(
trustAgent1, trustAgent2);
assertThat(mLockPatternUtils.getKnownTrustAgents(TEST_USER_ID)).containsExactly(
trustAgent1, trustAgent2);
}
@Test
public void newSystemTrustAgent_setToEnabledAndKnown() {
bootService();
ComponentName newAgentComponentName = ComponentName.unflattenFromString(
"com.android/.SystemTrustAgent");
addTrustAgent(newAgentComponentName, /* isSystemApp= */ true);
mMockContext.sendPackageChangedBroadcast(newAgentComponentName);
assertThat(mLockPatternUtils.getEnabledTrustAgents(TEST_USER_ID)).containsExactly(
newAgentComponentName);
assertThat(mLockPatternUtils.getKnownTrustAgents(TEST_USER_ID)).containsExactly(
newAgentComponentName);
}
@Test
public void newSystemTrustAgent_notEnabledWhenDefaultAgentIsSet() {
ComponentName defaultTrustAgent = ComponentName.unflattenFromString(
"com.user/.DefaultTrustAgent");
addTrustAgent(defaultTrustAgent, /* isSystemApp= */ false);
mMockContext.getOrCreateTestableResources().addOverride(
com.android.internal.R.string.config_defaultTrustAgent,
defaultTrustAgent.flattenToString());
bootService();
ComponentName newAgentComponentName = ComponentName.unflattenFromString(
"com.android/.SystemTrustAgent");
addTrustAgent(newAgentComponentName, /* isSystemApp= */ true);
mMockContext.sendPackageChangedBroadcast(newAgentComponentName);
assertThat(mLockPatternUtils.getEnabledTrustAgents(TEST_USER_ID)).containsExactly(
defaultTrustAgent);
assertThat(mLockPatternUtils.getKnownTrustAgents(TEST_USER_ID)).containsExactly(
defaultTrustAgent, newAgentComponentName);
}
@Test
public void newNonSystemTrustAgent_notEnabledButMarkedAsKnown() {
bootService();
ComponentName newAgentComponentName = ComponentName.unflattenFromString(
"com.user/.UserTrustAgent");
addTrustAgent(newAgentComponentName, /* isSystemApp= */ false);
mMockContext.sendPackageChangedBroadcast(newAgentComponentName);
assertThat(mLockPatternUtils.getEnabledTrustAgents(TEST_USER_ID)).isEmpty();
assertThat(mLockPatternUtils.getKnownTrustAgents(TEST_USER_ID)).containsExactly(
newAgentComponentName);
}
@Test
public void existingTrustAgentChanged_notEnabled() {
ComponentName systemTrustAgent1 = ComponentName.unflattenFromString(
"com.android/.SystemTrustAgent");
ComponentName systemTrustAgent2 = ComponentName.unflattenFromString(
"com.android/.AnotherSystemTrustAgent");
addTrustAgent(systemTrustAgent1, /* isSystemApp= */ true);
addTrustAgent(systemTrustAgent2, /* isSystemApp= */ true);
bootService();
// Simulate user turning off systemTrustAgent2
mLockPatternUtils.setEnabledTrustAgents(Collections.singletonList(systemTrustAgent1),
TEST_USER_ID);
mMockContext.sendPackageChangedBroadcast(systemTrustAgent2);
assertThat(mLockPatternUtils.getEnabledTrustAgents(TEST_USER_ID)).containsExactly(
systemTrustAgent1);
}
private void addTrustAgent(ComponentName agentComponentName, boolean isSystemApp) {
ApplicationInfo applicationInfo = new ApplicationInfo();
if (isSystemApp) {
applicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
}
ServiceInfo serviceInfo = new ServiceInfo();
serviceInfo.packageName = agentComponentName.getPackageName();
serviceInfo.name = agentComponentName.getClassName();
serviceInfo.applicationInfo = applicationInfo;
ResolveInfo resolveInfo = new ResolveInfo();
resolveInfo.serviceInfo = serviceInfo;
mTrustAgentResolveInfoList.add(resolveInfo);
}
private void initializeEnabledAgents(ComponentName... enabledAgents) {
mLockPatternUtils.setEnabledTrustAgents(Lists.newArrayList(enabledAgents), TEST_USER_ID);
Settings.Secure.putIntForUser(mMockContext.getContentResolver(),
Settings.Secure.TRUST_AGENTS_INITIALIZED, 1, TEST_USER_ID);
}
private void initializeKnownAgents(ComponentName... knownAgents) {
mLockPatternUtils.setKnownTrustAgents(Lists.newArrayList(knownAgents), TEST_USER_ID);
Settings.Secure.putIntForUser(mMockContext.getContentResolver(),
Settings.Secure.KNOWN_TRUST_AGENTS_INITIALIZED, 1, TEST_USER_ID);
}
private void bootService() {
mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
}
private void resetTrustAgentLockSettings() {
mLockPatternUtils.setEnabledTrustAgents(Collections.emptyList(), TEST_USER_ID);
mLockPatternUtils.setKnownTrustAgents(Collections.emptyList(), TEST_USER_ID);
}
/** A mock Context that allows the test process to send protected broadcasts. */
private static final class MockContext extends TestableContext {
private final ArrayList<BroadcastReceiver> mPackageChangedBroadcastReceivers =
new ArrayList<>();
MockContext(Context base) {
super(base);
}
@Override
@Nullable
public Intent registerReceiverAsUser(BroadcastReceiver receiver,
UserHandle user, IntentFilter filter, @Nullable String broadcastPermission,
@Nullable Handler scheduler) {
if (filter.hasAction(Intent.ACTION_PACKAGE_CHANGED)) {
mPackageChangedBroadcastReceivers.add(receiver);
}
return super.registerReceiverAsUser(receiver, user, filter, broadcastPermission,
scheduler);
}
void sendPackageChangedBroadcast(ComponentName changedComponent) {
Intent intent = new Intent(
Intent.ACTION_PACKAGE_CHANGED,
Uri.fromParts(URI_SCHEME_PACKAGE,
changedComponent.getPackageName(), /* fragment= */ null))
.putExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST,
new String[]{changedComponent.getClassName()})
.putExtra(Intent.EXTRA_USER_HANDLE, TEST_USER_ID)
.putExtra(Intent.EXTRA_UID, UserHandle.of(TEST_USER_ID).getUid(1234));
for (BroadcastReceiver receiver : mPackageChangedBroadcastReceivers) {
receiver.onReceive(this, intent);
}
}
}
}