summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jason Sun <jasonsun@google.com> 2022-09-21 21:37:29 +0000
committer Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> 2022-09-21 21:37:29 +0000
commit84435238c4a08c93b5f7aa7b752c6cb876b51df8 (patch)
tree871cba0f888c3212a22a5830800f3eeb6292a721
parent5b0ad2818a00803b7dd77a03ae315fbd4c6e4022 (diff)
parent73ce3e64f06f90c9e36e0bff405b05bc9ba8665a (diff)
Merge "Auto enable new system trust agents" into tm-qpr-dev am: 73ce3e64f0
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/19824313 Change-Id: I79539f4e42c07d9eb694389febb0b32c15a2b265 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--core/java/android/provider/Settings.java7
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java44
-rw-r--r--core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java64
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java1
-rw-r--r--services/core/java/com/android/server/trust/TrustManagerService.java102
-rw-r--r--services/tests/mockingservicestests/AndroidManifest.xml5
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java334
7 files changed, 530 insertions, 27 deletions
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index c4437c37c27c..34ca5d46cae1 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7427,6 +7427,13 @@ public final class Settings {
"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.
* @deprecated This identifier is poorly initialized and has
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index a94b30707604..1235b602cde9 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -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;
}
/**
diff --git a/core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java
index 940ca96fac4f..4679a9ea6f66 100644
--- a/core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java
@@ -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() {
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 2209ff596cb5..8e82b8b5219a 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -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,
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 3707c8e42e04..7170773edca4 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -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) {
@@ -1826,7 +1906,13 @@ public class TrustManagerService extends SystemService {
}
@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);
diff --git a/services/tests/mockingservicestests/AndroidManifest.xml b/services/tests/mockingservicestests/AndroidManifest.xml
index 07b763dcd85b..33ac73560968 100644
--- a/services/tests/mockingservicestests/AndroidManifest.xml
+++ b/services/tests/mockingservicestests/AndroidManifest.xml
@@ -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" />
diff --git a/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
new file mode 100644
index 000000000000..33870f1d3b86
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
@@ -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);
+ }
+ }
+ }
+}