diff options
17 files changed, 82 insertions, 51 deletions
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp index 19fa64073183..14f48711e068 100644 --- a/cmds/statsd/Android.bp +++ b/cmds/statsd/Android.bp @@ -65,7 +65,7 @@ cc_defaults { "src/condition/condition_util.cpp", "src/condition/SimpleConditionTracker.cpp", "src/condition/ConditionWizard.cpp", - "src/condition/StateTracker.cpp", + "src/condition/StateConditionTracker.cpp", "src/config/ConfigKey.cpp", "src/config/ConfigListener.cpp", "src/config/ConfigManager.cpp", @@ -227,7 +227,7 @@ cc_test { "tests/FieldValue_test.cpp", "tests/condition/CombinationConditionTracker_test.cpp", "tests/condition/SimpleConditionTracker_test.cpp", - "tests/condition/StateTracker_test.cpp", + "tests/condition/StateConditionTracker_test.cpp", "tests/condition/ConditionTimer_test.cpp", "tests/metrics/OringDurationTracker_test.cpp", "tests/metrics/MaxDurationTracker_test.cpp", diff --git a/cmds/statsd/src/condition/StateTracker.cpp b/cmds/statsd/src/condition/StateConditionTracker.cpp index 18c7178dd7d7..7f3eeddba831 100644 --- a/cmds/statsd/src/condition/StateTracker.cpp +++ b/cmds/statsd/src/condition/StateConditionTracker.cpp @@ -16,7 +16,7 @@ #define DEBUG false // STOPSHIP if true #include "Log.h" -#include "StateTracker.h" +#include "StateConditionTracker.h" #include "guardrail/StatsdStats.h" namespace android { @@ -27,7 +27,7 @@ using std::string; using std::unordered_set; using std::vector; -StateTracker::StateTracker(const ConfigKey& key, const int64_t& id, const int index, +StateConditionTracker::StateConditionTracker(const ConfigKey& key, const int64_t& id, const int index, const SimplePredicate& simplePredicate, const unordered_map<int64_t, int>& trackerNameIndexMap, const vector<Matcher> primaryKeys) @@ -69,19 +69,19 @@ StateTracker::StateTracker(const ConfigKey& key, const int64_t& id, const int in mInitialized = true; } -StateTracker::~StateTracker() { - VLOG("~StateTracker()"); +StateConditionTracker::~StateConditionTracker() { + VLOG("~StateConditionTracker()"); } -bool StateTracker::init(const vector<Predicate>& allConditionConfig, +bool StateConditionTracker::init(const vector<Predicate>& allConditionConfig, const vector<sp<ConditionTracker>>& allConditionTrackers, const unordered_map<int64_t, int>& conditionIdIndexMap, vector<bool>& stack) { return mInitialized; } -void StateTracker::dumpState() { - VLOG("StateTracker %lld DUMP:", (long long)mConditionId); +void StateConditionTracker::dumpState() { + VLOG("StateConditionTracker %lld DUMP:", (long long)mConditionId); for (const auto& value : mSlicedState) { VLOG("\t%s -> %s", value.first.toString().c_str(), value.second.toString().c_str()); } @@ -95,7 +95,7 @@ void StateTracker::dumpState() { } } -bool StateTracker::hitGuardRail(const HashableDimensionKey& newKey) { +bool StateConditionTracker::hitGuardRail(const HashableDimensionKey& newKey) { if (mSlicedState.find(newKey) != mSlicedState.end()) { // if the condition is not sliced or the key is not new, we are good! return false; @@ -114,7 +114,7 @@ bool StateTracker::hitGuardRail(const HashableDimensionKey& newKey) { return false; } -void StateTracker::evaluateCondition(const LogEvent& event, +void StateConditionTracker::evaluateCondition(const LogEvent& event, const vector<MatchingState>& eventMatcherValues, const vector<sp<ConditionTracker>>& mAllConditions, vector<ConditionState>& conditionCache, @@ -135,7 +135,7 @@ void StateTracker::evaluateCondition(const LogEvent& event, return; } - VLOG("StateTracker evaluate event %s", event.ToString().c_str()); + VLOG("StateConditionTracker evaluate event %s", event.ToString().c_str()); // Primary key can exclusive fields must be simple fields. so there won't be more than // one keys matched. @@ -151,7 +151,7 @@ void StateTracker::evaluateCondition(const LogEvent& event, } hitGuardRail(primaryKey); - VLOG("StateTracker: key %s state %s", primaryKey.toString().c_str(), state.toString().c_str()); + VLOG("StateConditionTracker: key %s state %s", primaryKey.toString().c_str(), state.toString().c_str()); auto it = mSlicedState.find(primaryKey); if (it == mSlicedState.end()) { @@ -176,7 +176,7 @@ void StateTracker::evaluateCondition(const LogEvent& event, return; } -void StateTracker::isConditionMet( +void StateConditionTracker::isConditionMet( const ConditionKey& conditionParameters, const vector<sp<ConditionTracker>>& allConditions, const bool isPartialLink, vector<ConditionState>& conditionCache) const { diff --git a/cmds/statsd/src/condition/StateTracker.h b/cmds/statsd/src/condition/StateConditionTracker.h index 5ae4441713cd..0efe1fb3fcb2 100644 --- a/cmds/statsd/src/condition/StateTracker.h +++ b/cmds/statsd/src/condition/StateConditionTracker.h @@ -25,14 +25,14 @@ namespace android { namespace os { namespace statsd { -class StateTracker : public virtual ConditionTracker { +class StateConditionTracker : public virtual ConditionTracker { public: - StateTracker(const ConfigKey& key, const int64_t& id, const int index, + StateConditionTracker(const ConfigKey& key, const int64_t& id, const int index, const SimplePredicate& simplePredicate, const std::unordered_map<int64_t, int>& trackerNameIndexMap, const vector<Matcher> primaryKeys); - ~StateTracker(); + ~StateConditionTracker(); bool init(const std::vector<Predicate>& allConditionConfig, const std::vector<sp<ConditionTracker>>& allConditionTrackers, @@ -46,8 +46,8 @@ public: std::vector<bool>& changedCache) override; /** - * Note: dimensionFields will be ignored in StateTracker, because we demand metrics - * must take the entire dimension fields from StateTracker. This is to make implementation + * Note: dimensionFields will be ignored in StateConditionTracker, because we demand metrics + * must take the entire dimension fields from StateConditionTracker. This is to make implementation * simple and efficient. * * For example: wakelock duration by uid process states: @@ -109,7 +109,7 @@ private: // maps from [primary_key] to [primary_key, exclusive_state]. std::unordered_map<HashableDimensionKey, HashableDimensionKey> mSlicedState; - FRIEND_TEST(StateTrackerTest, TestStateChange); + FRIEND_TEST(StateConditionTrackerTest, TestStateChange); }; } // namespace statsd diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp index dd32c08faba3..111b4346151a 100644 --- a/cmds/statsd/src/metrics/metrics_manager_util.cpp +++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp @@ -21,7 +21,7 @@ #include "../condition/CombinationConditionTracker.h" #include "../condition/SimpleConditionTracker.h" -#include "../condition/StateTracker.h" +#include "../condition/StateConditionTracker.h" #include "../external/StatsPullerManager.h" #include "../matchers/CombinationLogMatchingTracker.h" #include "../matchers/SimpleLogMatchingTracker.h" @@ -182,13 +182,13 @@ bool initLogTrackers(const StatsdConfig& config, const UidMap& uidMap, } /** - * A StateTracker is built from a SimplePredicate which has only "start", and no "stop" + * A StateConditionTracker is built from a SimplePredicate which has only "start", and no "stop" * or "stop_all". The start must be an atom matcher that matches a state atom. It must * have dimension, the dimension must be the state atom's primary fields plus exclusive state - * field. For example, the StateTracker is used in tracking UidProcessState and ScreenState. + * field. For example, the StateConditionTracker is used in tracking UidProcessState and ScreenState. * */ -bool isStateTracker(const SimplePredicate& simplePredicate, vector<Matcher>* primaryKeys) { +bool isStateConditionTracker(const SimplePredicate& simplePredicate, vector<Matcher>* primaryKeys) { // 1. must not have "stop". must have "dimension" if (!simplePredicate.has_stop() && simplePredicate.has_dimensions()) { auto it = android::util::AtomsInfo::kStateAtomsFieldOptions.find( @@ -240,8 +240,8 @@ bool initConditions(const ConfigKey& key, const StatsdConfig& config, switch (condition.contents_case()) { case Predicate::ContentsCase::kSimplePredicate: { vector<Matcher> primaryKeys; - if (isStateTracker(condition.simple_predicate(), &primaryKeys)) { - allConditionTrackers.push_back(new StateTracker(key, condition.id(), index, + if (isStateConditionTracker(condition.simple_predicate(), &primaryKeys)) { + allConditionTrackers.push_back(new StateConditionTracker(key, condition.id(), index, condition.simple_predicate(), logTrackerMap, primaryKeys)); } else { diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h index 028231ff908c..3704969039c4 100644 --- a/cmds/statsd/src/metrics/metrics_manager_util.h +++ b/cmds/statsd/src/metrics/metrics_manager_util.h @@ -113,7 +113,7 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap& vector<int>& metricsWithActivation, std::set<int64_t>& noReportMetricIds); -bool isStateTracker(const SimplePredicate& simplePredicate, std::vector<Matcher>* primaryKeys); +bool isStateConditionTracker(const SimplePredicate& simplePredicate, std::vector<Matcher>* primaryKeys); } // namespace statsd } // namespace os diff --git a/cmds/statsd/tests/condition/StateTracker_test.cpp b/cmds/statsd/tests/condition/StateConditionTracker_test.cpp index 9a66254afce0..fbf6efdcf966 100644 --- a/cmds/statsd/tests/condition/StateTracker_test.cpp +++ b/cmds/statsd/tests/condition/StateConditionTracker_test.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "src/condition/StateTracker.h" +#include "src/condition/StateConditionTracker.h" #include "tests/statsd_test_util.h" #include <gmock/gmock.h> @@ -50,7 +50,7 @@ void makeUidProcStateEvent(int32_t uid, int32_t state, LogEvent* event) { event->init(); } -TEST(StateTrackerTest, TestStateChange) { +TEST(StateConditionTrackerTest, TestStateChange) { int uid1 = 111; int uid2 = 222; @@ -60,7 +60,7 @@ TEST(StateTrackerTest, TestStateChange) { trackerNameIndexMap[StringToId("UidProcState")] = 0; vector<Matcher> primaryFields; primaryFields.push_back(getSimpleMatcher(kUidProcTag, 1)); - StateTracker tracker(ConfigKey(12, 123), 123, 0, getUidProcStatePredicate(), + StateConditionTracker tracker(ConfigKey(12, 123), 123, 0, getUidProcStatePredicate(), trackerNameIndexMap, primaryFields); LogEvent event(kUidProcTag, 0 /*timestamp*/); diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java index 2efebf6457ab..7e22dd9f0ac8 100644 --- a/core/java/android/view/DisplayInfo.java +++ b/core/java/android/view/DisplayInfo.java @@ -18,6 +18,7 @@ package android.view; import static android.view.DisplayInfoProto.APP_HEIGHT; import static android.view.DisplayInfoProto.APP_WIDTH; +import static android.view.DisplayInfoProto.FLAGS; import static android.view.DisplayInfoProto.LOGICAL_HEIGHT; import static android.view.DisplayInfoProto.LOGICAL_WIDTH; import static android.view.DisplayInfoProto.NAME; @@ -708,6 +709,7 @@ public final class DisplayInfo implements Parcelable { protoOutputStream.write(APP_WIDTH, appWidth); protoOutputStream.write(APP_HEIGHT, appHeight); protoOutputStream.write(NAME, name); + protoOutputStream.write(FLAGS, flags); protoOutputStream.end(token); } diff --git a/core/proto/android/view/displayinfo.proto b/core/proto/android/view/displayinfo.proto index 49c0a290c368..984be2a2e417 100644 --- a/core/proto/android/view/displayinfo.proto +++ b/core/proto/android/view/displayinfo.proto @@ -33,4 +33,5 @@ message DisplayInfoProto { // The human-readable name of the display. // Eg: "Built-in Screen" optional string name = 5; + optional int32 flags = 6; } diff --git a/packages/CarSystemUI/res/values/integers_car.xml b/packages/CarSystemUI/res/values/integers_car.xml index 862ba751aa55..fb67b302a4ae 100644 --- a/packages/CarSystemUI/res/values/integers_car.xml +++ b/packages/CarSystemUI/res/values/integers_car.xml @@ -32,6 +32,6 @@ at will result in remaining closed the panel if released--> <integer name="notification_settle_close_percentage">80</integer> <!-- The delay before the unlock dialog pops up --> - <integer name="unlock_dialog_delay_ms">3000</integer> + <integer name="unlock_dialog_delay_ms">0</integer> </resources> diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java index b135f7b27c3f..effea6a877b8 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java @@ -159,8 +159,11 @@ public class TileLifecycleManager extends BroadcastReceiver implements mBindTryCount++; try { mIsBound = mContext.bindServiceAsUser(mIntent, this, - Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE - | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS, mUser); + Context.BIND_AUTO_CREATE + | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE + | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS + | Context.BIND_WAIVE_PRIORITY, + mUser); } catch (SecurityException e) { Log.e(TAG, "Failed to bind to service", e); mIsBound = false; diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index f5f6625c8728..d9933d741e2a 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -4497,18 +4497,27 @@ class ActivityStack extends ConfigurationContainer { * then skip running tasks that match those types. */ void getRunningTasks(List<TaskRecord> tasksOut, @ActivityType int ignoreActivityType, - @WindowingMode int ignoreWindowingMode, int callingUid, boolean allowed) { + @WindowingMode int ignoreWindowingMode, int callingUid, boolean allowed, + boolean crossUser) { boolean focusedStack = mRootActivityContainer.getTopDisplayFocusedStack() == this; boolean topTask = true; + int userId = UserHandle.getUserId(callingUid); for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { final TaskRecord task = mTaskHistory.get(taskNdx); if (task.getTopActivity() == null) { // Skip if there are no activities in the task continue; } - if (!allowed && !task.isActivityTypeHome() && task.effectiveUid != callingUid) { - // Skip if the caller can't fetch this task - continue; + if (task.effectiveUid != callingUid) { + if (task.userId != userId && !crossUser) { + // Skip if the caller does not have cross user permission + continue; + } + if (!allowed && !task.isActivityTypeHome()) { + // Skip if the caller isn't allowed to fetch this task, except for the home + // task which we always return. + continue; + } } if (ignoreActivityType != ACTIVITY_TYPE_UNDEFINED && task.getActivityType() == ignoreActivityType) { diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index ee56c0902e78..76c215db035b 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -19,6 +19,8 @@ package com.android.server.wm; import static android.Manifest.permission.BIND_VOICE_INTERACTION; import static android.Manifest.permission.CHANGE_CONFIGURATION; import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS; +import static android.Manifest.permission.INTERACT_ACROSS_USERS; +import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS; import static android.Manifest.permission.READ_FRAME_BUFFER; @@ -2508,15 +2510,16 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @WindowConfiguration.ActivityType int ignoreActivityType, @WindowConfiguration.WindowingMode int ignoreWindowingMode) { final int callingUid = Binder.getCallingUid(); + final int callingPid = Binder.getCallingPid(); + final boolean crossUser = isCrossUserAllowed(callingPid, callingUid); ArrayList<ActivityManager.RunningTaskInfo> list = new ArrayList<>(); synchronized (mGlobalLock) { if (DEBUG_ALL) Slog.v(TAG, "getTasks: max=" + maxNum); - final boolean allowed = isGetTasksAllowed("getTasks", Binder.getCallingPid(), - callingUid); + final boolean allowed = isGetTasksAllowed("getTasks", callingPid, callingUid); mRootActivityContainer.getRunningTasks(maxNum, list, ignoreActivityType, - ignoreWindowingMode, callingUid, allowed); + ignoreWindowingMode, callingUid, allowed, crossUser); } return list; @@ -3546,6 +3549,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return allowed; } + boolean isCrossUserAllowed(int pid, int uid) { + return checkPermission(INTERACT_ACROSS_USERS, pid, uid) == PERMISSION_GRANTED + || checkPermission(INTERACT_ACROSS_USERS_FULL, pid, uid) == PERMISSION_GRANTED; + } + private PendingAssistExtras enqueueAssistContext(int requestType, Intent intent, String hint, IAssistDataReceiver receiver, Bundle receiverExtras, IBinder activityToken, boolean focused, boolean newSessionId, int userHandle, Bundle args, long timeout, diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java index eb5d096aa781..a626f5410c91 100644 --- a/services/core/java/com/android/server/wm/RootActivityContainer.java +++ b/services/core/java/com/android/server/wm/RootActivityContainer.java @@ -2260,9 +2260,9 @@ class RootActivityContainer extends ConfigurationContainer void getRunningTasks(int maxNum, List<ActivityManager.RunningTaskInfo> list, @WindowConfiguration.ActivityType int ignoreActivityType, @WindowConfiguration.WindowingMode int ignoreWindowingMode, int callingUid, - boolean allowed) { + boolean allowed, boolean crossUser) { mStackSupervisor.getRunningTasks().getTasks(maxNum, list, ignoreActivityType, - ignoreWindowingMode, mActivityDisplays, callingUid, allowed); + ignoreWindowingMode, mActivityDisplays, callingUid, allowed, crossUser); } void sendPowerHintForLaunchStartIfNeeded(boolean forceSend, ActivityRecord targetActivity) { diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java index 3bf437d38bcc..22a9c32a830f 100644 --- a/services/core/java/com/android/server/wm/RunningTasks.java +++ b/services/core/java/com/android/server/wm/RunningTasks.java @@ -40,7 +40,7 @@ class RunningTasks { void getTasks(int maxNum, List<RunningTaskInfo> list, @ActivityType int ignoreActivityType, @WindowingMode int ignoreWindowingMode, ArrayList<ActivityDisplay> activityDisplays, - int callingUid, boolean allowed) { + int callingUid, boolean allowed, boolean crossUser) { // Return early if there are no tasks to fetch if (maxNum <= 0) { return; @@ -55,7 +55,7 @@ class RunningTasks { final ActivityStack stack = display.getChildAt(stackNdx); mTmpStackTasks.clear(); stack.getRunningTasks(mTmpStackTasks, ignoreActivityType, ignoreWindowingMode, - callingUid, allowed); + callingUid, allowed, crossUser); mTmpSortedSet.addAll(mTmpStackTasks); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java index fb4e330f06ed..6b9cb7dab4a6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java @@ -1289,10 +1289,10 @@ public class RecentTasksTest extends ActivityTestsBase { @Override void getTasks(int maxNum, List<RunningTaskInfo> list, int ignoreActivityType, int ignoreWindowingMode, ArrayList<ActivityDisplay> activityDisplays, - int callingUid, boolean allowed) { + int callingUid, boolean allowed, boolean crossUser) { mLastAllowed = allowed; super.getTasks(maxNum, list, ignoreActivityType, ignoreWindowingMode, activityDisplays, - callingUid, allowed); + callingUid, allowed, crossUser); } } } diff --git a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java index dc964806b7a9..cdd4c2424421 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java @@ -77,7 +77,7 @@ public class RunningTasksTest extends ActivityTestsBase { final int numFetchTasks = 5; ArrayList<RunningTaskInfo> tasks = new ArrayList<>(); mRunningTasks.getTasks(5, tasks, ACTIVITY_TYPE_UNDEFINED, WINDOWING_MODE_UNDEFINED, - displays, -1 /* callingUid */, true /* allowed */); + displays, -1 /* callingUid */, true /* allowed */, true /*crossUser */); assertThat(tasks).hasSize(numFetchTasks); for (int i = 0; i < numFetchTasks; i++) { assertEquals(numTasks - i - 1, tasks.get(i).id); @@ -87,7 +87,7 @@ public class RunningTasksTest extends ActivityTestsBase { // and does not crash tasks.clear(); mRunningTasks.getTasks(100, tasks, ACTIVITY_TYPE_UNDEFINED, WINDOWING_MODE_UNDEFINED, - displays, -1 /* callingUid */, true /* allowed */); + displays, -1 /* callingUid */, true /* allowed */, true /* crossUser */); assertThat(tasks).hasSize(numTasks); for (int i = 0; i < numTasks; i++) { assertEquals(numTasks - i - 1, tasks.get(i).id); diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java index b2e5a62849e7..bc98f06ebc56 100644 --- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java +++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java @@ -28,6 +28,8 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.concurrent.TimeUnit; + /** * Runs the staged rollback tests. */ @@ -99,9 +101,15 @@ public class StagedRollbackTest extends BaseHostJUnit4Test { // crash system_server enough times to trigger a rollback crashProcess("system_server", NATIVE_CRASHES_THRESHOLD); - // Rollback should be committed automatically now - // Give time for rollback to be committed - assertTrue(getDevice().waitForDeviceNotAvailable(60000)); + // Rollback should be committed automatically now. + // Give time for rollback to be committed. This could take a while, + // because we need all of the following to happen: + // 1. system_server comes back up and boot completes. + // 2. Rollback health observer detects updatable crashing signal. + // 3. Staged rollback session becomes ready. + // 4. Device actually reboots. + // So we give a generous timeout here. + assertTrue(getDevice().waitForDeviceNotAvailable(TimeUnit.MINUTES.toMillis(5))); getDevice().waitForDeviceAvailable(); // verify rollback committed |