From fab29c6f1b296202ba52901ef119ae6260a1a61d Mon Sep 17 00:00:00 2001 From: JW Wang Date: Tue, 19 Nov 2019 16:17:41 +0800 Subject: Rewrite blockRollbackManager (1/n) This is an effort to fix flaky testEnableRollbackTimeoutFailsRollback. RollbackManager#blockRollbackManager doesn't work as intended because PackageManagerService can't dispatch ENABLE_ROLLBACK_TIMEOUT until abortBroadcast is called by RollbackManagerServiceImpl which happens after blocking is finished. See https://b.corp.google.com/issues/144732395#comment4 for a detailed explanation. blockRollbackManager is rewritten such that: 1. blocking takes effect only after ACTION_PACKAGE_ENABLE_ROLLBACK is received. 2. allows tests which involves multi-package install where multiple ACTION_PACKAGE_ENABLE_ROLLBACK will be broadcasted. 3. ENABLE_ROLLBACK_TIMEOUT now will be dispatched without waiting for blocking to finish. Bug: 144732395 Test: atest RollbackTest Change-Id: Ib262bc8c8f17563a4911f780c9d2e6a34803335a --- .../rollback/RollbackManagerServiceImpl.java | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java index 198bb146c9b2..01f29dcd4ffe 100644 --- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java @@ -49,6 +49,7 @@ import android.os.UserManager; import android.provider.DeviceConfig; import android.util.ArraySet; import android.util.IntArray; +import android.util.LongArrayQueue; import android.util.Slog; import android.util.SparseBooleanArray; @@ -126,6 +127,11 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { private final RollbackPackageHealthObserver mPackageHealthObserver; private final AppDataRollbackHelper mAppDataRollbackHelper; + // The # of milli-seconds to sleep for each received ACTION_PACKAGE_ENABLE_ROLLBACK. + // Used by #blockRollbackManager to test timeout in enabling rollbacks. + // Accessed on the handler thread only. + private final LongArrayQueue mSleepDuration = new LongArrayQueue(); + // This field stores the difference in Millis between the uptime (millis since device // has booted) and current time (device wall clock) - it's used to update rollback // timestamps when the time is changed, by the user or by change of timezone. @@ -182,6 +188,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { File newPackageCodePath = new File(intent.getData().getPath()); + queueSleepIfNeeded(); + getHandler().post(() -> { boolean success = enableRollback(installFlags, newPackageCodePath, user, token); @@ -413,6 +421,19 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { mContext.enforceCallingOrSelfPermission( Manifest.permission.TEST_MANAGE_ROLLBACKS, "blockRollbackManager"); + getHandler().post(() -> { + mSleepDuration.addLast(millis); + }); + } + + private void queueSleepIfNeeded() { + if (mSleepDuration.size() == 0) { + return; + } + long millis = mSleepDuration.removeFirst(); + if (millis <= 0) { + return; + } getHandler().post(() -> { try { Thread.sleep(millis); @@ -1034,6 +1055,9 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { makeRollbackAvailable(rollback); } } + + // Clear the queue so it will never be leaked to next tests. + mSleepDuration.clear(); } } -- cgit v1.2.3-59-g8ed1b From 517bb2b25bb067e40e993637352f1028488d3878 Mon Sep 17 00:00:00 2001 From: JW Wang Date: Thu, 21 Nov 2019 14:34:34 +0800 Subject: Test child sessions time out in enabling rollback (2/n) The rollback shouldn't be available if any of the child sessions times out in enabling rollback. Bug: 144732395 Test: atest RollbackTest Change-Id: Id899f3c1ec100fcdcad1f24f2701f95b1c49bc69 --- .../com/android/tests/rollback/RollbackTest.java | 44 ++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java index 599ee56afdb3..abe6c6152da5 100644 --- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java +++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java @@ -1054,4 +1054,48 @@ public class RollbackTest { InstallUtils.dropShellPermissionIdentity(); } } + + @Test + public void testEnableRollbackTimeoutFailsRollback_MultiPackage() throws Exception { + try { + InstallUtils.adoptShellPermissionIdentity( + Manifest.permission.INSTALL_PACKAGES, + Manifest.permission.DELETE_PACKAGES, + Manifest.permission.TEST_MANAGE_ROLLBACKS, + Manifest.permission.MANAGE_ROLLBACKS, + Manifest.permission.WRITE_DEVICE_CONFIG); + + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK, + PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS, + Long.toString(5000), false /* makeDefault*/); + RollbackManager rm = RollbackUtils.getRollbackManager(); + + Uninstall.packages(TestApp.A, TestApp.B); + Install.multi(TestApp.A1, TestApp.B1).commit(); + waitForUnavailableRollback(TestApp.A); + + // Block the 2nd session for 10s so it will not be able to enable the rollback in time. + rm.blockRollbackManager(TimeUnit.SECONDS.toMillis(0)); + rm.blockRollbackManager(TimeUnit.SECONDS.toMillis(10)); + Install.multi(TestApp.A2, TestApp.B2).setEnableRollback().commit(); + + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2); + assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2); + + // Give plenty of time for RollbackManager to unblock and attempt + // to make the rollback available before asserting that the + // rollback was not made available. + Thread.sleep(TimeUnit.SECONDS.toMillis(2)); + + List available = rm.getAvailableRollbacks(); + assertThat(getUniqueRollbackInfoForPackage(available, TestApp.A)).isNull(); + assertThat(getUniqueRollbackInfoForPackage(available, TestApp.B)).isNull(); + } finally { + //setting the timeout back to default + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK, + PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS, + null, false /* makeDefault*/); + InstallUtils.dropShellPermissionIdentity(); + } + } } -- cgit v1.2.3-59-g8ed1b