Auto enable new system trust agents
Previously we only auto enable factory system trust agents when the devices is booted for the first time. This change added logic to detect newly installed/enabled trust agents, and enable them if appropriate. Fixes: b/243705470 Test: atest FrameworksMockingServicesTests:TrustManagerServiceTest Change-Id: I3c345a44cfcfccc6f7e2507ba37e378b6b16bd98
This commit is contained in:
@@ -7406,6 +7406,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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user