summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Harshit Mahajan <harshitmahajan@google.com> 2023-04-12 16:26:59 +0000
committer Harshit Mahajan <harshitmahajan@google.com> 2023-04-13 15:40:05 +0000
commit47c9f8cdd99a2a12c395e49d4d39d643e362fa49 (patch)
treeb50949dc66351dbfc70ad2598a2d43ce91c248d6
parent19f87108534ecd0c6d4279c9a437ccb198bad0b4 (diff)
Fix RollbackPackageHealthObserver for rollback-all
Making RollbackPackageHealthObserver should start monitoring all packages if any rollback is available. Handling the cases when a package without rollbacks fails and mitigationCount equals 1. Setting 'sys.attempting_reboot' property when we reboot after committing the rollback, which would prevent factory reset to execute synchronously. Test: atest RollbackPackageHealthObserverTest Bug: b/264997660 Change-Id: I12780acf8dcedb2b139d19339bc5acc632129ea0
-rw-r--r--services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java44
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java63
2 files changed, 94 insertions, 13 deletions
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index e437be8e01b5..2007079ea5ca 100644
--- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -17,10 +17,12 @@
package com.android.server.rollback;
import android.annotation.AnyThread;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.WorkerThread;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
import android.content.rollback.PackageRollbackInfo;
@@ -68,6 +70,9 @@ import java.util.function.Consumer;
final class RollbackPackageHealthObserver implements PackageHealthObserver {
private static final String TAG = "RollbackPackageHealthObserver";
private static final String NAME = "rollback-observer";
+ private static final String PROP_ATTEMPTING_REBOOT = "sys.attempting_reboot";
+ private static final int PERSISTENT_MASK = ApplicationInfo.FLAG_PERSISTENT
+ | ApplicationInfo.FLAG_SYSTEM;
private final Context mContext;
private final Handler mHandler;
@@ -114,10 +119,10 @@ final class RollbackPackageHealthObserver implements PackageHealthObserver {
// For native crashes, we will directly roll back any available rollbacks
// Note: For non-native crashes the rollback-all step has higher impact
impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_30;
- } else if (mitigationCount == 1 && getAvailableRollback(failedPackage) != null) {
+ } else if (getAvailableRollback(failedPackage) != null) {
// Rollback is available, we may get a callback into #execute
impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_30;
- } else if (mitigationCount > 1 && anyRollbackAvailable) {
+ } else if (anyRollbackAvailable) {
// If any rollbacks are available, we will commit them
impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_70;
}
@@ -133,14 +138,10 @@ final class RollbackPackageHealthObserver implements PackageHealthObserver {
return true;
}
- if (mitigationCount == 1) {
- RollbackInfo rollback = getAvailableRollback(failedPackage);
- if (rollback == null) {
- Slog.w(TAG, "Expected rollback but no valid rollback found for " + failedPackage);
- return false;
- }
+ RollbackInfo rollback = getAvailableRollback(failedPackage);
+ if (rollback != null) {
mHandler.post(() -> rollbackPackage(rollback, failedPackage, rollbackReason));
- } else if (mitigationCount > 1) {
+ } else {
mHandler.post(() -> rollbackAll(rollbackReason));
}
@@ -153,6 +154,30 @@ final class RollbackPackageHealthObserver implements PackageHealthObserver {
return NAME;
}
+ @Override
+ public boolean isPersistent() {
+ return true;
+ }
+
+ @Override
+ public boolean mayObservePackage(String packageName) {
+ if (mContext.getSystemService(RollbackManager.class)
+ .getAvailableRollbacks().isEmpty()) {
+ return false;
+ }
+ return isPersistentSystemApp(packageName);
+ }
+
+ 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 void assertInWorkerThread() {
Preconditions.checkState(mHandler.getLooper().isCurrentThread());
}
@@ -425,6 +450,7 @@ final class RollbackPackageHealthObserver implements PackageHealthObserver {
markStagedSessionHandled(rollback.getRollbackId());
// Wait for all pending staged sessions to get handled before rebooting.
if (isPendingStagedSessionsEmpty()) {
+ SystemProperties.set(PROP_ATTEMPTING_REBOOT, "true");
mContext.getSystemService(PowerManager.class).reboot("Rollback staged install");
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java b/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java
index 541b07782b29..a14073006c31 100644
--- a/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java
@@ -21,10 +21,14 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
import android.content.rollback.PackageRollbackInfo;
import android.content.rollback.RollbackInfo;
@@ -71,9 +75,12 @@ public class RollbackPackageHealthObserverTest {
RollbackInfo mRollbackInfo;
@Mock
PackageRollbackInfo mPackageRollbackInfo;
+ @Mock
+ PackageManager mMockPackageManager;
private MockitoSession mSession;
private static final String APP_A = "com.package.a";
+ private static final String APP_B = "com.package.b";
private static final long VERSION_CODE = 1L;
private static final String LOG_TAG = "RollbackPackageHealthObserverTest";
@@ -116,7 +123,7 @@ public class RollbackPackageHealthObserverTest {
RollbackPackageHealthObserver observer =
spy(new RollbackPackageHealthObserver(mMockContext));
VersionedPackage testFailedPackage = new VersionedPackage(APP_A, VERSION_CODE);
-
+ VersionedPackage secondFailedPackage = new VersionedPackage(APP_B, VERSION_CODE);
when(mMockContext.getSystemService(RollbackManager.class)).thenReturn(mRollbackManager);
@@ -137,13 +144,16 @@ public class RollbackPackageHealthObserverTest {
assertEquals(PackageWatchdog.PackageHealthObserverImpact.USER_IMPACT_LEVEL_30,
observer.onHealthCheckFailed(null,
PackageWatchdog.FAILURE_REASON_NATIVE_CRASH, 1));
- // non-native crash
+ // non-native crash for the package
assertEquals(PackageWatchdog.PackageHealthObserverImpact.USER_IMPACT_LEVEL_30,
observer.onHealthCheckFailed(testFailedPackage,
PackageWatchdog.FAILURE_REASON_APP_CRASH, 1));
- // Second non-native crash again
+ // non-native crash for a different package
assertEquals(PackageWatchdog.PackageHealthObserverImpact.USER_IMPACT_LEVEL_70,
- observer.onHealthCheckFailed(testFailedPackage,
+ observer.onHealthCheckFailed(secondFailedPackage,
+ PackageWatchdog.FAILURE_REASON_APP_CRASH, 1));
+ assertEquals(PackageWatchdog.PackageHealthObserverImpact.USER_IMPACT_LEVEL_70,
+ observer.onHealthCheckFailed(secondFailedPackage,
PackageWatchdog.FAILURE_REASON_APP_CRASH, 2));
// Subsequent crashes when rollbacks have completed
when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of());
@@ -152,6 +162,51 @@ public class RollbackPackageHealthObserverTest {
PackageWatchdog.FAILURE_REASON_APP_CRASH, 3));
}
+ @Test
+ public void testIsPersistent() {
+ RollbackPackageHealthObserver observer =
+ spy(new RollbackPackageHealthObserver(mMockContext));
+ assertTrue(observer.isPersistent());
+ }
+
+ @Test
+ public void testMayObservePackage_withoutAnyRollback() {
+ RollbackPackageHealthObserver observer =
+ spy(new RollbackPackageHealthObserver(mMockContext));
+ when(mMockContext.getSystemService(RollbackManager.class)).thenReturn(mRollbackManager);
+ when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of());
+ assertFalse(observer.mayObservePackage(APP_A));
+ }
+
+ @Test
+ public void testMayObservePackage_forPersistentApp()
+ throws PackageManager.NameNotFoundException {
+ RollbackPackageHealthObserver observer =
+ spy(new RollbackPackageHealthObserver(mMockContext));
+ ApplicationInfo info = new ApplicationInfo();
+ info.flags = ApplicationInfo.FLAG_PERSISTENT | ApplicationInfo.FLAG_SYSTEM;
+ when(mMockContext.getSystemService(RollbackManager.class)).thenReturn(mRollbackManager);
+ when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(mRollbackInfo));
+ when(mRollbackInfo.getPackages()).thenReturn(List.of(mPackageRollbackInfo));
+ when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+ when(mMockPackageManager.getApplicationInfo(APP_A, 0)).thenReturn(info);
+ assertTrue(observer.mayObservePackage(APP_A));
+ }
+
+ @Test
+ public void testMayObservePackage_forNonPersistentApp()
+ throws PackageManager.NameNotFoundException {
+ RollbackPackageHealthObserver observer =
+ spy(new RollbackPackageHealthObserver(mMockContext));
+ when(mMockContext.getSystemService(RollbackManager.class)).thenReturn(mRollbackManager);
+ when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(mRollbackInfo));
+ when(mRollbackInfo.getPackages()).thenReturn(List.of(mPackageRollbackInfo));
+ when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+ when(mMockPackageManager.getApplicationInfo(APP_A, 0))
+ .thenThrow(new PackageManager.NameNotFoundException());
+ assertFalse(observer.mayObservePackage(APP_A));
+ }
+
/**
* Test that isAutomaticRollbackDenied works correctly when packages that are not
* denied are sent.