Merge "Restrict Rescue Party factory reset packages" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
67306315aa
@@ -327,18 +327,23 @@ public class RescueParty {
|
||||
}
|
||||
}
|
||||
|
||||
private static int getMaxRescueLevel() {
|
||||
return SystemProperties.getBoolean(PROP_DISABLE_FACTORY_RESET_FLAG, false)
|
||||
? LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS : LEVEL_FACTORY_RESET;
|
||||
private static int getMaxRescueLevel(boolean mayPerformFactoryReset) {
|
||||
if (!mayPerformFactoryReset
|
||||
|| SystemProperties.getBoolean(PROP_DISABLE_FACTORY_RESET_FLAG, false)) {
|
||||
return LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS;
|
||||
}
|
||||
return LEVEL_FACTORY_RESET;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the rescue level to perform if this is the n-th attempt at mitigating failure.
|
||||
*
|
||||
* @param mitigationCount: the mitigation attempt number (1 = first attempt etc.)
|
||||
* @param mayPerformFactoryReset: whether or not a factory reset may be performed for the given
|
||||
* failure.
|
||||
* @return the rescue level for the n-th mitigation attempt.
|
||||
*/
|
||||
private static int getRescueLevel(int mitigationCount) {
|
||||
private static int getRescueLevel(int mitigationCount, boolean mayPerformFactoryReset) {
|
||||
if (mitigationCount == 1) {
|
||||
return LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS;
|
||||
} else if (mitigationCount == 2) {
|
||||
@@ -346,9 +351,9 @@ public class RescueParty {
|
||||
} else if (mitigationCount == 3) {
|
||||
return LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS;
|
||||
} else if (mitigationCount == 4) {
|
||||
return Math.min(getMaxRescueLevel(), LEVEL_WARM_REBOOT);
|
||||
return Math.min(getMaxRescueLevel(mayPerformFactoryReset), LEVEL_WARM_REBOOT);
|
||||
} else if (mitigationCount >= 5) {
|
||||
return Math.min(getMaxRescueLevel(), LEVEL_FACTORY_RESET);
|
||||
return Math.min(getMaxRescueLevel(mayPerformFactoryReset), LEVEL_FACTORY_RESET);
|
||||
} else {
|
||||
Slog.w(TAG, "Expected positive mitigation count, was " + mitigationCount);
|
||||
return LEVEL_NONE;
|
||||
@@ -614,7 +619,8 @@ public class RescueParty {
|
||||
@FailureReasons int failureReason, int mitigationCount) {
|
||||
if (!isDisabled() && (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH
|
||||
|| failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING)) {
|
||||
return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount));
|
||||
return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
|
||||
mayPerformFactoryReset(failedPackage)));
|
||||
} else {
|
||||
return PackageHealthObserverImpact.USER_IMPACT_NONE;
|
||||
}
|
||||
@@ -628,7 +634,8 @@ public class RescueParty {
|
||||
}
|
||||
if (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH
|
||||
|| failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING) {
|
||||
final int level = getRescueLevel(mitigationCount);
|
||||
final int level = getRescueLevel(mitigationCount,
|
||||
mayPerformFactoryReset(failedPackage));
|
||||
executeRescueLevel(mContext,
|
||||
failedPackage == null ? null : failedPackage.getPackageName(), level);
|
||||
return true;
|
||||
@@ -653,12 +660,7 @@ public class RescueParty {
|
||||
} catch (PackageManager.NameNotFoundException ignore) {
|
||||
}
|
||||
|
||||
try {
|
||||
ApplicationInfo info = pm.getApplicationInfo(packageName, 0);
|
||||
return (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
return isPersistentSystemApp(packageName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -666,7 +668,7 @@ public class RescueParty {
|
||||
if (isDisabled()) {
|
||||
return PackageHealthObserverImpact.USER_IMPACT_NONE;
|
||||
}
|
||||
return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount));
|
||||
return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount, true));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -674,7 +676,8 @@ public class RescueParty {
|
||||
if (isDisabled()) {
|
||||
return false;
|
||||
}
|
||||
executeRescueLevel(mContext, /*failedPackage=*/ null, getRescueLevel(mitigationCount));
|
||||
executeRescueLevel(mContext, /*failedPackage=*/ null,
|
||||
getRescueLevel(mitigationCount, true));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -683,6 +686,29 @@ public class RescueParty {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the failing package is non-null and performing a reboot or
|
||||
* prompting a factory reset is an acceptable mitigation strategy for the package's
|
||||
* failure, {@code false} otherwise.
|
||||
*/
|
||||
private boolean mayPerformFactoryReset(@Nullable VersionedPackage failingPackage) {
|
||||
if (failingPackage == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isPersistentSystemApp(failingPackage.getPackageName());
|
||||
}
|
||||
|
||||
private boolean isPersistentSystemApp(@NonNull String packageName) {
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
try {
|
||||
ApplicationInfo info = pm.getApplicationInfo(packageName, 0);
|
||||
return (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void recordDeviceConfigAccess(@NonNull String callingPackage,
|
||||
@NonNull String namespace) {
|
||||
// Record it in calling packages to namespace map
|
||||
|
||||
@@ -37,6 +37,8 @@ import static org.mockito.Mockito.times;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.VersionedPackage;
|
||||
import android.os.Bundle;
|
||||
import android.os.RecoverySystem;
|
||||
@@ -83,6 +85,8 @@ public class RescuePartyTest {
|
||||
private static final String CALLING_PACKAGE1 = "com.package.name1";
|
||||
private static final String CALLING_PACKAGE2 = "com.package.name2";
|
||||
private static final String CALLING_PACKAGE3 = "com.package.name3";
|
||||
private static final String PERSISTENT_PACKAGE = "com.persistent.package";
|
||||
private static final String NON_PERSISTENT_PACKAGE = "com.nonpersistent.package";
|
||||
private static final String NAMESPACE1 = "namespace1";
|
||||
private static final String NAMESPACE2 = "namespace2";
|
||||
private static final String NAMESPACE3 = "namespace3";
|
||||
@@ -103,6 +107,8 @@ public class RescuePartyTest {
|
||||
private PackageWatchdog mMockPackageWatchdog;
|
||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||
private ContentResolver mMockContentResolver;
|
||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||
private PackageManager mPackageManager;
|
||||
|
||||
@Captor
|
||||
private ArgumentCaptor<RemoteCallback> mMonitorCallbackCaptor;
|
||||
@@ -129,6 +135,17 @@ public class RescuePartyTest {
|
||||
mNamespacesWiped = new HashSet<>();
|
||||
|
||||
when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver);
|
||||
when(mMockContext.getPackageManager()).thenReturn(mPackageManager);
|
||||
ApplicationInfo persistentApplicationInfo = new ApplicationInfo();
|
||||
persistentApplicationInfo.flags |=
|
||||
ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_PERSISTENT;
|
||||
|
||||
// If the package name is PERSISTENT_PACKAGE, then set the flags to be persistent and
|
||||
// system. Don't set any flags otherwise.
|
||||
when(mPackageManager.getApplicationInfo(eq(PERSISTENT_PACKAGE),
|
||||
anyInt())).thenReturn(persistentApplicationInfo);
|
||||
when(mPackageManager.getApplicationInfo(eq(NON_PERSISTENT_PACKAGE),
|
||||
anyInt())).thenReturn(new ApplicationInfo());
|
||||
// Reset observer instance to get new mock context on every run
|
||||
RescuePartyObserver.reset();
|
||||
|
||||
@@ -241,28 +258,52 @@ public class RescuePartyTest {
|
||||
|
||||
@Test
|
||||
public void testPersistentAppCrashDetectionWithExecutionForAllRescueLevels() {
|
||||
notePersistentAppCrash(1);
|
||||
noteAppCrash(1, true);
|
||||
|
||||
verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, /*resetNamespaces=*/ null,
|
||||
/*configResetVerifiedTimesMap=*/ null);
|
||||
|
||||
notePersistentAppCrash(2);
|
||||
noteAppCrash(2, true);
|
||||
|
||||
verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES, /*resetNamespaces=*/ null,
|
||||
/*configResetVerifiedTimesMap=*/ null);
|
||||
|
||||
notePersistentAppCrash(3);
|
||||
noteAppCrash(3, true);
|
||||
|
||||
verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, /*resetNamespaces=*/ null,
|
||||
/*configResetVerifiedTimesMap=*/ null);
|
||||
|
||||
notePersistentAppCrash(4);
|
||||
noteAppCrash(4, true);
|
||||
assertTrue(RescueParty.isRebootPropertySet());
|
||||
|
||||
notePersistentAppCrash(5);
|
||||
noteAppCrash(5, true);
|
||||
assertTrue(RescueParty.isFactoryResetPropertySet());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonPersistentAppOnlyPerformsFlagResets() {
|
||||
noteAppCrash(1, false);
|
||||
|
||||
verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, /*resetNamespaces=*/ null,
|
||||
/*configResetVerifiedTimesMap=*/ null);
|
||||
|
||||
noteAppCrash(2, false);
|
||||
|
||||
verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES, /*resetNamespaces=*/ null,
|
||||
/*configResetVerifiedTimesMap=*/ null);
|
||||
|
||||
noteAppCrash(3, false);
|
||||
|
||||
verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, /*resetNamespaces=*/ null,
|
||||
/*configResetVerifiedTimesMap=*/ null);
|
||||
|
||||
noteAppCrash(4, false);
|
||||
assertFalse(RescueParty.isRebootPropertySet());
|
||||
|
||||
noteAppCrash(5, false);
|
||||
assertFalse(RescueParty.isFactoryResetPropertySet());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonPersistentAppCrashDetectionWithScopedResets() {
|
||||
RescueParty.onSettingsProviderPublished(mMockContext);
|
||||
@@ -311,11 +352,11 @@ public class RescuePartyTest {
|
||||
|
||||
observer.execute(new VersionedPackage(
|
||||
CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 4);
|
||||
assertTrue(RescueParty.isRebootPropertySet());
|
||||
assertFalse(RescueParty.isRebootPropertySet());
|
||||
|
||||
observer.execute(new VersionedPackage(
|
||||
CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 5);
|
||||
assertTrue(RescueParty.isFactoryResetPropertySet());
|
||||
assertFalse(RescueParty.isFactoryResetPropertySet());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -376,11 +417,11 @@ public class RescuePartyTest {
|
||||
|
||||
observer.execute(new VersionedPackage(
|
||||
CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 4);
|
||||
assertTrue(RescueParty.isRebootPropertySet());
|
||||
assertFalse(RescueParty.isRebootPropertySet());
|
||||
|
||||
observer.execute(new VersionedPackage(
|
||||
CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 5);
|
||||
assertTrue(RescueParty.isFactoryResetPropertySet());
|
||||
assertFalse(RescueParty.isFactoryResetPropertySet());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -627,9 +668,10 @@ public class RescuePartyTest {
|
||||
RescuePartyObserver.getInstance(mMockContext).executeBootLoopMitigation(mitigationCount);
|
||||
}
|
||||
|
||||
private void notePersistentAppCrash(int mitigationCount) {
|
||||
private void noteAppCrash(int mitigationCount, boolean isPersistent) {
|
||||
String packageName = isPersistent ? PERSISTENT_PACKAGE : NON_PERSISTENT_PACKAGE;
|
||||
RescuePartyObserver.getInstance(mMockContext).execute(new VersionedPackage(
|
||||
"com.package.name", 1), PackageWatchdog.FAILURE_REASON_APP_CRASH, mitigationCount);
|
||||
packageName, 1), PackageWatchdog.FAILURE_REASON_APP_CRASH, mitigationCount);
|
||||
}
|
||||
|
||||
private Bundle getConfigAccessBundle(String callingPackage, String namespace) {
|
||||
|
||||
Reference in New Issue
Block a user