blob: b50c22ea09e31fb2fd54d3e74443dcdc6dd89d69 [file] [log] [blame]
Richard Uhlere95d0552018-12-27 15:03:41 +00001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.rollback;
18
Richard Uhler1fc10c12019-03-18 11:38:46 +000019import android.Manifest;
JW Wang53e89c92019-11-28 19:53:45 +080020import android.annotation.AnyThread;
Richard Uhler2a5facc2019-02-18 11:33:03 +000021import android.annotation.NonNull;
JW Wang1ac3d112020-02-07 15:52:36 +080022import android.annotation.Nullable;
JW Wang53e89c92019-11-28 19:53:45 +080023import android.annotation.WorkerThread;
Richard Uhlere95d0552018-12-27 15:03:41 +000024import android.app.AppOpsManager;
25import android.content.BroadcastReceiver;
26import android.content.Context;
Richard Uhlere95d0552018-12-27 15:03:41 +000027import android.content.Intent;
28import android.content.IntentFilter;
29import android.content.IntentSender;
Richard Uhlerab009ea2019-02-25 12:11:05 +000030import android.content.pm.ApplicationInfo;
Richard Uhler1fc10c12019-03-18 11:38:46 +000031import android.content.pm.ModuleInfo;
Richard Uhlere95d0552018-12-27 15:03:41 +000032import android.content.pm.PackageInfo;
33import android.content.pm.PackageInstaller;
34import android.content.pm.PackageManager;
35import android.content.pm.PackageManagerInternal;
36import android.content.pm.PackageParser;
37import android.content.pm.ParceledListSlice;
Richard Uhler82913b72019-04-01 13:02:31 +010038import android.content.pm.UserInfo;
Richard Uhlera7e9b2d2019-01-22 17:20:58 +000039import android.content.pm.VersionedPackage;
Richard Uhlere95d0552018-12-27 15:03:41 +000040import android.content.rollback.IRollbackManager;
Richard Uhlere95d0552018-12-27 15:03:41 +000041import android.content.rollback.RollbackInfo;
Richard Uhler2a48c292019-01-28 17:33:48 +000042import android.content.rollback.RollbackManager;
Richard Uhlere95d0552018-12-27 15:03:41 +000043import android.os.Binder;
Richard Uhlere95d0552018-12-27 15:03:41 +000044import android.os.Environment;
45import android.os.Handler;
JW Wangc63c1da2020-01-15 15:44:25 +080046import android.os.HandlerExecutor;
Richard Uhlere95d0552018-12-27 15:03:41 +000047import android.os.HandlerThread;
Narayan Kamath869f7062019-01-10 12:24:15 +000048import android.os.Process;
shafikda5e4ee2019-02-12 16:29:01 +000049import android.os.SystemClock;
shafik74fec182019-03-14 16:29:48 +000050import android.os.UserHandle;
Richard Uhler798b8592019-06-07 14:04:43 +010051import android.os.UserManager;
shafik0ad18b82019-01-24 16:27:24 +000052import android.provider.DeviceConfig;
Narayan Kamathc034fe92019-01-23 10:48:17 +000053import android.util.IntArray;
JW Wang5d17a762020-02-03 16:02:33 +080054import android.util.Log;
JW Wangfab29c62019-11-19 16:17:41 +080055import android.util.LongArrayQueue;
shafikbb771fb2019-06-05 14:59:57 +010056import android.util.Slog;
Richard Uhlerb9d54472019-01-22 12:50:08 +000057import android.util.SparseBooleanArray;
Richard Uhlere95d0552018-12-27 15:03:41 +000058
59import com.android.internal.annotations.GuardedBy;
Oli Lan8753d822019-11-01 11:33:53 +000060import com.android.internal.util.DumpUtils;
shafik60046002019-03-12 17:54:10 +000061import com.android.internal.util.IndentingPrintWriter;
Richard Uhlere95d0552018-12-27 15:03:41 +000062import com.android.server.LocalServices;
Gavin Corkeryefb3ff12019-12-02 18:15:24 +000063import com.android.server.PackageWatchdog;
JW Wang9b51b732019-12-11 17:14:15 +080064import com.android.server.SystemConfig;
shafik18b627e2019-05-01 20:41:48 +010065import com.android.server.Watchdog;
Oli Lan592cd9d2020-03-05 12:08:42 +000066import com.android.server.pm.ApexManager;
Narayan Kamath869f7062019-01-10 12:24:15 +000067import com.android.server.pm.Installer;
Richard Uhlere95d0552018-12-27 15:03:41 +000068
Richard Uhlere95d0552018-12-27 15:03:41 +000069import java.io.File;
shafik60046002019-03-12 17:54:10 +000070import java.io.FileDescriptor;
shafik60046002019-03-12 17:54:10 +000071import java.io.PrintWriter;
Richard Uhlerb9d54472019-01-22 12:50:08 +000072import java.security.SecureRandom;
Richard Uhlere95d0552018-12-27 15:03:41 +000073import java.time.Instant;
Richard Uhlere95d0552018-12-27 15:03:41 +000074import java.time.temporal.ChronoUnit;
75import java.util.ArrayList;
JW Wang12d0c3e2019-12-02 21:01:35 +080076import java.util.Arrays;
Richard Uhler1924d6d2019-04-26 10:20:12 +010077import java.util.HashSet;
Richard Uhlere95d0552018-12-27 15:03:41 +000078import java.util.Iterator;
79import java.util.List;
Richard Uhlerb9d54472019-01-22 12:50:08 +000080import java.util.Random;
Richard Uhlere9aaf632019-03-01 16:03:01 +000081import java.util.Set;
Richard Uhler74ee2992019-07-01 15:21:44 +010082import java.util.concurrent.CountDownLatch;
JW Wangc63c1da2020-01-15 15:44:25 +080083import java.util.concurrent.Executor;
Narayan Kamathfcd4a042019-02-01 14:16:37 +000084import java.util.concurrent.LinkedBlockingQueue;
shafik0ad18b82019-01-24 16:27:24 +000085import java.util.concurrent.TimeUnit;
Richard Uhlere95d0552018-12-27 15:03:41 +000086
87/**
88 * Implementation of service that manages APK level rollbacks.
JW Wang53e89c92019-11-28 19:53:45 +080089 *
90 * Threading model:
91 *
92 * - @AnyThread annotates thread-safe methods.
93 * - @WorkerThread annotates methods that should be called from the handler thread only.
Richard Uhlere95d0552018-12-27 15:03:41 +000094 */
95class RollbackManagerServiceImpl extends IRollbackManager.Stub {
96
97 private static final String TAG = "RollbackManager";
JW Wang5d17a762020-02-03 16:02:33 +080098 private static final boolean LOCAL_LOGV = Log.isLoggable(TAG, Log.VERBOSE);
Richard Uhlere95d0552018-12-27 15:03:41 +000099
Matt Pape6686f1f2019-07-09 10:41:20 -0700100 // Rollbacks expire after 14 days.
shafik0ad18b82019-01-24 16:27:24 +0000101 private static final long DEFAULT_ROLLBACK_LIFETIME_DURATION_MILLIS =
Matt Pape6686f1f2019-07-09 10:41:20 -0700102 TimeUnit.DAYS.toMillis(14);
Richard Uhlere95d0552018-12-27 15:03:41 +0000103
104 // Lock used to synchronize accesses to in-memory rollback data
105 // structures. By convention, methods with the suffix "Locked" require
106 // mLock is held when they are called.
107 private final Object mLock = new Object();
108
shafik0ad18b82019-01-24 16:27:24 +0000109 // No need for guarding with lock because value is only accessed in handler thread
110 // and the value will be written on boot complete. Initialization here happens before
111 // handler threads are running so that's fine.
112 private long mRollbackLifetimeDurationInMillis = DEFAULT_ROLLBACK_LIFETIME_DURATION_MILLIS;
113
shafik18b627e2019-05-01 20:41:48 +0100114 private static final long HANDLER_THREAD_TIMEOUT_DURATION_MILLIS =
115 TimeUnit.MINUTES.toMillis(10);
116
Richard Uhlerb9d54472019-01-22 12:50:08 +0000117 // Used for generating rollback IDs.
118 private final Random mRandom = new SecureRandom();
119
120 // Set of allocated rollback ids
121 @GuardedBy("mLock")
122 private final SparseBooleanArray mAllocatedRollbackIds = new SparseBooleanArray();
123
Richard Uhler6f8a33b2019-02-26 10:40:36 +0000124 // The list of all rollbacks, including available and committed rollbacks.
Richard Uhlere95d0552018-12-27 15:03:41 +0000125 @GuardedBy("mLock")
Richard Uhler8d512ee2019-07-19 14:55:01 +0100126 private final List<Rollback> mRollbacks;
Richard Uhlere95d0552018-12-27 15:03:41 +0000127
Oli Lan0bf44862019-08-29 14:25:38 +0100128 // Apk sessions from a staged session with no matching rollback.
129 @GuardedBy("mLock")
130 private final IntArray mOrphanedApkSessionIds = new IntArray();
131
Richard Uhler28e73232019-01-21 16:48:55 +0000132 private final RollbackStore mRollbackStore;
Richard Uhlere95d0552018-12-27 15:03:41 +0000133
134 private final Context mContext;
135 private final HandlerThread mHandlerThread;
JW Wangc63c1da2020-01-15 15:44:25 +0800136 private final Executor mExecutor;
Narayan Kamath869f7062019-01-10 12:24:15 +0000137 private final Installer mInstaller;
Zimuzoc4073cc2019-01-18 18:39:18 +0000138 private final RollbackPackageHealthObserver mPackageHealthObserver;
Nikita Ioffe952aa7b2019-01-28 19:49:56 +0000139 private final AppDataRollbackHelper mAppDataRollbackHelper;
Richard Uhlere95d0552018-12-27 15:03:41 +0000140
JW Wangfab29c62019-11-19 16:17:41 +0800141 // The # of milli-seconds to sleep for each received ACTION_PACKAGE_ENABLE_ROLLBACK.
142 // Used by #blockRollbackManager to test timeout in enabling rollbacks.
143 // Accessed on the handler thread only.
144 private final LongArrayQueue mSleepDuration = new LongArrayQueue();
145
shafikda5e4ee2019-02-12 16:29:01 +0000146 // This field stores the difference in Millis between the uptime (millis since device
Richard Uhler8d512ee2019-07-19 14:55:01 +0100147 // has booted) and current time (device wall clock) - it's used to update rollback
shafikda5e4ee2019-02-12 16:29:01 +0000148 // timestamps when the time is changed, by the user or by change of timezone.
149 // No need for guarding with lock because value is only accessed in handler thread.
150 private long mRelativeBootTime = calculateRelativeBootTime();
151
Richard Uhlere95d0552018-12-27 15:03:41 +0000152 RollbackManagerServiceImpl(Context context) {
153 mContext = context;
Narayan Kamath869f7062019-01-10 12:24:15 +0000154 // Note that we're calling onStart here because this object is only constructed on
155 // SystemService#onStart.
156 mInstaller = new Installer(mContext);
157 mInstaller.onStart();
shafik18b627e2019-05-01 20:41:48 +0100158
Richard Uhler28e73232019-01-21 16:48:55 +0000159 mRollbackStore = new RollbackStore(new File(Environment.getDataDirectory(), "rollback"));
Richard Uhlere95d0552018-12-27 15:03:41 +0000160
Zimuzoc4073cc2019-01-18 18:39:18 +0000161 mPackageHealthObserver = new RollbackPackageHealthObserver(mContext);
Nikita Ioffe952aa7b2019-01-28 19:49:56 +0000162 mAppDataRollbackHelper = new AppDataRollbackHelper(mInstaller);
Zimuzoc4073cc2019-01-18 18:39:18 +0000163
Richard Uhler74ee2992019-07-01 15:21:44 +0100164 // Load rollback data from device storage.
165 synchronized (mLock) {
Richard Uhler8d512ee2019-07-19 14:55:01 +0100166 mRollbacks = mRollbackStore.loadRollbacks();
JW Wang529d3aa2020-02-10 16:22:40 +0800167 if (!context.getPackageManager().isDeviceUpgrading()) {
168 for (Rollback rollback : mRollbacks) {
169 mAllocatedRollbackIds.put(rollback.info.getRollbackId(), true);
170 }
171 } else {
172 // Delete rollbacks when build fingerprint has changed.
173 for (Rollback rollback : mRollbacks) {
174 rollback.delete(mAppDataRollbackHelper);
175 }
176 mRollbacks.clear();
Richard Uhler74ee2992019-07-01 15:21:44 +0100177 }
178 }
179
180 // Kick off and start monitoring the handler thread.
181 mHandlerThread = new HandlerThread("RollbackManagerServiceHandler");
182 mHandlerThread.start();
183 Watchdog.getInstance().addThread(getHandler(), HANDLER_THREAD_TIMEOUT_DURATION_MILLIS);
JW Wangc63c1da2020-01-15 15:44:25 +0800184 mExecutor = new HandlerExecutor(getHandler());
Richard Uhlere95d0552018-12-27 15:03:41 +0000185
Richard Uhler82913b72019-04-01 13:02:31 +0100186 for (UserInfo userInfo : UserManager.get(mContext).getUsers(true)) {
187 registerUserCallbacks(userInfo.getUserHandle());
188 }
Richard Uhlere95d0552018-12-27 15:03:41 +0000189
190 IntentFilter enableRollbackFilter = new IntentFilter();
191 enableRollbackFilter.addAction(Intent.ACTION_PACKAGE_ENABLE_ROLLBACK);
192 try {
193 enableRollbackFilter.addDataType("application/vnd.android.package-archive");
194 } catch (IntentFilter.MalformedMimeTypeException e) {
shafikbb771fb2019-06-05 14:59:57 +0100195 Slog.e(TAG, "addDataType", e);
Richard Uhlere95d0552018-12-27 15:03:41 +0000196 }
197
198 mContext.registerReceiver(new BroadcastReceiver() {
199 @Override
200 public void onReceive(Context context, Intent intent) {
201 if (Intent.ACTION_PACKAGE_ENABLE_ROLLBACK.equals(intent.getAction())) {
202 int token = intent.getIntExtra(
203 PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN, -1);
JW Wang635382e2020-02-17 16:30:52 +0800204 int sessionId = intent.getIntExtra(
205 PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_SESSION_ID, -1);
Richard Uhler82913b72019-04-01 13:02:31 +0100206
JW Wangfab29c62019-11-19 16:17:41 +0800207 queueSleepIfNeeded();
208
Richard Uhlere95d0552018-12-27 15:03:41 +0000209 getHandler().post(() -> {
JW Wang298239b2020-02-17 17:08:02 +0800210 boolean success = enableRollback(sessionId);
Richard Uhlere95d0552018-12-27 15:03:41 +0000211 int ret = PackageManagerInternal.ENABLE_ROLLBACK_SUCCEEDED;
212 if (!success) {
213 ret = PackageManagerInternal.ENABLE_ROLLBACK_FAILED;
214 }
215
216 PackageManagerInternal pm = LocalServices.getService(
217 PackageManagerInternal.class);
218 pm.setEnableRollbackCode(token, ret);
219 });
220
221 // We're handling the ordered broadcast. Abort the
222 // broadcast because there is no need for it to go to
223 // anyone else.
224 abortBroadcast();
225 }
226 }
227 }, enableRollbackFilter, null, getHandler());
shafikda5e4ee2019-02-12 16:29:01 +0000228
shafik4831ad72019-05-03 17:36:42 +0100229 IntentFilter enableRollbackTimedOutFilter = new IntentFilter();
230 enableRollbackTimedOutFilter.addAction(Intent.ACTION_CANCEL_ENABLE_ROLLBACK);
231
232 mContext.registerReceiver(new BroadcastReceiver() {
233 @Override
234 public void onReceive(Context context, Intent intent) {
235 if (Intent.ACTION_CANCEL_ENABLE_ROLLBACK.equals(intent.getAction())) {
JW Wang635382e2020-02-17 16:30:52 +0800236 int sessionId = intent.getIntExtra(
237 PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_SESSION_ID, -1);
JW Wang12d0c3e2019-12-02 21:01:35 +0800238 if (LOCAL_LOGV) {
JW Wang298239b2020-02-17 17:08:02 +0800239 Slog.v(TAG, "broadcast=ACTION_CANCEL_ENABLE_ROLLBACK id=" + sessionId);
JW Wang12d0c3e2019-12-02 21:01:35 +0800240 }
shafik4831ad72019-05-03 17:36:42 +0100241 synchronized (mLock) {
JW Wang635382e2020-02-17 16:30:52 +0800242 Rollback rollback = getRollbackForSessionLocked(sessionId);
243 if (rollback != null && rollback.isEnabling()) {
244 mRollbacks.remove(rollback);
245 rollback.delete(mAppDataRollbackHelper);
shafik4831ad72019-05-03 17:36:42 +0100246 }
247 }
248 }
249 }
250 }, enableRollbackTimedOutFilter, null, getHandler());
251
shafik8aea1ad2019-05-21 12:34:50 +0100252 IntentFilter userAddedIntentFilter = new IntentFilter(Intent.ACTION_USER_ADDED);
253 mContext.registerReceiver(new BroadcastReceiver() {
254 @Override
255 public void onReceive(Context context, Intent intent) {
256 if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
257 final int newUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
258 if (newUserId == -1) {
259 return;
260 }
261 registerUserCallbacks(UserHandle.of(newUserId));
262 }
263 }
264 }, userAddedIntentFilter, null, getHandler());
265
shafikda5e4ee2019-02-12 16:29:01 +0000266 registerTimeChangeReceiver();
Richard Uhlere95d0552018-12-27 15:03:41 +0000267 }
268
JW Wang53e89c92019-11-28 19:53:45 +0800269 @AnyThread
Richard Uhler82913b72019-04-01 13:02:31 +0100270 private void registerUserCallbacks(UserHandle user) {
271 Context context = getContextAsUser(user);
272 if (context == null) {
shafikbb771fb2019-06-05 14:59:57 +0100273 Slog.e(TAG, "Unable to register user callbacks for user " + user);
Richard Uhler82913b72019-04-01 13:02:31 +0100274 return;
275 }
276
Richard Uhler82913b72019-04-01 13:02:31 +0100277 context.getPackageManager().getPackageInstaller()
278 .registerSessionCallback(new SessionCallback(), getHandler());
279
280 IntentFilter filter = new IntentFilter();
281 filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
282 filter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
283 filter.addDataScheme("package");
284 context.registerReceiver(new BroadcastReceiver() {
285 @Override
286 public void onReceive(Context context, Intent intent) {
287 String action = intent.getAction();
288 if (Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
289 String packageName = intent.getData().getSchemeSpecificPart();
JW Wang12d0c3e2019-12-02 21:01:35 +0800290 if (LOCAL_LOGV) {
291 Slog.v(TAG, "broadcast=ACTION_PACKAGE_REPLACED" + " pkg=" + packageName);
292 }
Richard Uhler82913b72019-04-01 13:02:31 +0100293 onPackageReplaced(packageName);
294 }
295 if (Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(action)) {
296 String packageName = intent.getData().getSchemeSpecificPart();
JW Wang12d0c3e2019-12-02 21:01:35 +0800297 if (LOCAL_LOGV) {
298 Slog.v(TAG, "broadcast=ACTION_PACKAGE_FULLY_REMOVED"
299 + " pkg=" + packageName);
300 }
Richard Uhler82913b72019-04-01 13:02:31 +0100301 onPackageFullyRemoved(packageName);
302 }
303 }
304 }, filter, null, getHandler());
305 }
306
Richard Uhlere95d0552018-12-27 15:03:41 +0000307 @Override
Richard Uhler150ad982019-01-23 15:16:10 +0000308 public ParceledListSlice getAvailableRollbacks() {
Richard Uhler1fc10c12019-03-18 11:38:46 +0000309 enforceManageRollbacks("getAvailableRollbacks");
Richard Uhlere95d0552018-12-27 15:03:41 +0000310 synchronized (mLock) {
Richard Uhler150ad982019-01-23 15:16:10 +0000311 List<RollbackInfo> rollbacks = new ArrayList<>();
Richard Uhler6f8a33b2019-02-26 10:40:36 +0000312 for (int i = 0; i < mRollbacks.size(); ++i) {
Richard Uhler8d512ee2019-07-19 14:55:01 +0100313 Rollback rollback = mRollbacks.get(i);
Oli Lan4af2f752019-09-27 10:39:32 +0100314 if (rollback.isAvailable()) {
315 rollbacks.add(rollback.info);
Richard Uhler60ac7062019-02-05 13:25:39 +0000316 }
Richard Uhlere95d0552018-12-27 15:03:41 +0000317 }
Richard Uhler150ad982019-01-23 15:16:10 +0000318 return new ParceledListSlice<>(rollbacks);
Richard Uhlere95d0552018-12-27 15:03:41 +0000319 }
Richard Uhlere95d0552018-12-27 15:03:41 +0000320 }
321
322 @Override
Richard Uhlerf498dab2019-06-28 10:55:45 +0100323 public ParceledListSlice<RollbackInfo> getRecentlyCommittedRollbacks() {
Richard Uhler1fc10c12019-03-18 11:38:46 +0000324 enforceManageRollbacks("getRecentlyCommittedRollbacks");
Richard Uhlere95d0552018-12-27 15:03:41 +0000325
326 synchronized (mLock) {
Richard Uhler6f8a33b2019-02-26 10:40:36 +0000327 List<RollbackInfo> rollbacks = new ArrayList<>();
328 for (int i = 0; i < mRollbacks.size(); ++i) {
Richard Uhler8d512ee2019-07-19 14:55:01 +0100329 Rollback rollback = mRollbacks.get(i);
Oli Lan4af2f752019-09-27 10:39:32 +0100330 if (rollback.isCommitted()) {
331 rollbacks.add(rollback.info);
Richard Uhler6f8a33b2019-02-26 10:40:36 +0000332 }
333 }
Richard Uhlere95d0552018-12-27 15:03:41 +0000334 return new ParceledListSlice<>(rollbacks);
335 }
336 }
337
338 @Override
Richard Uhlerbf5b5c42019-01-28 15:26:37 +0000339 public void commitRollback(int rollbackId, ParceledListSlice causePackages,
340 String callerPackageName, IntentSender statusReceiver) {
Richard Uhlerf498dab2019-06-28 10:55:45 +0100341 enforceManageRollbacks("commitRollback");
Richard Uhlere95d0552018-12-27 15:03:41 +0000342
343 final int callingUid = Binder.getCallingUid();
344 AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
345 appOps.checkPackage(callingUid, callerPackageName);
346
347 getHandler().post(() ->
Richard Uhlerbf5b5c42019-01-28 15:26:37 +0000348 commitRollbackInternal(rollbackId, causePackages.getList(),
349 callerPackageName, statusReceiver));
Richard Uhlere95d0552018-12-27 15:03:41 +0000350 }
351
JW Wang53e89c92019-11-28 19:53:45 +0800352 @AnyThread
shafikda5e4ee2019-02-12 16:29:01 +0000353 private void registerTimeChangeReceiver() {
354 final BroadcastReceiver timeChangeIntentReceiver = new BroadcastReceiver() {
355 @Override
356 public void onReceive(Context context, Intent intent) {
357 final long oldRelativeBootTime = mRelativeBootTime;
358 mRelativeBootTime = calculateRelativeBootTime();
359 final long timeDifference = mRelativeBootTime - oldRelativeBootTime;
360
361 synchronized (mLock) {
Richard Uhler8d512ee2019-07-19 14:55:01 +0100362 Iterator<Rollback> iter = mRollbacks.iterator();
shafikda5e4ee2019-02-12 16:29:01 +0000363 while (iter.hasNext()) {
Richard Uhler8d512ee2019-07-19 14:55:01 +0100364 Rollback rollback = iter.next();
Oli Lan4af2f752019-09-27 10:39:32 +0100365 rollback.setTimestamp(
366 rollback.getTimestamp().plusMillis(timeDifference));
shafikda5e4ee2019-02-12 16:29:01 +0000367 }
shafikda5e4ee2019-02-12 16:29:01 +0000368 }
369 }
370 };
371 final IntentFilter filter = new IntentFilter();
372 filter.addAction(Intent.ACTION_TIME_CHANGED);
373 mContext.registerReceiver(timeChangeIntentReceiver, filter,
374 null /* broadcastPermission */, getHandler());
375 }
376
JW Wang53e89c92019-11-28 19:53:45 +0800377 @AnyThread
shafikda5e4ee2019-02-12 16:29:01 +0000378 private static long calculateRelativeBootTime() {
379 return System.currentTimeMillis() - SystemClock.elapsedRealtime();
380 }
381
Richard Uhlere95d0552018-12-27 15:03:41 +0000382 /**
Richard Uhlere87368e2019-01-24 16:34:14 +0000383 * Performs the actual work to commit a rollback.
Richard Uhlere95d0552018-12-27 15:03:41 +0000384 * The work is done on the current thread. This may be a long running
385 * operation.
386 */
JW Wang53e89c92019-11-28 19:53:45 +0800387 @WorkerThread
Richard Uhlerbf5b5c42019-01-28 15:26:37 +0000388 private void commitRollbackInternal(int rollbackId, List<VersionedPackage> causePackages,
Richard Uhlere95d0552018-12-27 15:03:41 +0000389 String callerPackageName, IntentSender statusReceiver) {
JW Wang12d0c3e2019-12-02 21:01:35 +0800390 Slog.i(TAG, "commitRollback id=" + rollbackId + " caller=" + callerPackageName);
Richard Uhlere95d0552018-12-27 15:03:41 +0000391
Richard Uhler8d512ee2019-07-19 14:55:01 +0100392 Rollback rollback = getRollbackForId(rollbackId);
Oli Lan8c0084d2019-09-11 13:38:43 +0100393 if (rollback == null) {
Oli Lan7363a622019-09-13 10:06:12 +0100394 sendFailure(
395 mContext, statusReceiver, RollbackManager.STATUS_FAILURE_ROLLBACK_UNAVAILABLE,
Richard Uhler2a48c292019-01-28 17:33:48 +0000396 "Rollback unavailable");
Narayan Kamathbc36f8d2019-01-23 12:00:08 +0000397 return;
398 }
Oli Lan4af2f752019-09-27 10:39:32 +0100399 rollback.commit(mContext, causePackages, callerPackageName, statusReceiver);
Richard Uhlere95d0552018-12-27 15:03:41 +0000400 }
401
402 @Override
403 public void reloadPersistedData() {
404 mContext.enforceCallingOrSelfPermission(
Richard Uhler1fc10c12019-03-18 11:38:46 +0000405 Manifest.permission.TEST_MANAGE_ROLLBACKS,
Richard Uhlere95d0552018-12-27 15:03:41 +0000406 "reloadPersistedData");
407
Richard Uhler74ee2992019-07-01 15:21:44 +0100408 CountDownLatch latch = new CountDownLatch(1);
shafik6d61f5e2019-02-26 09:33:26 +0000409 getHandler().post(() -> {
Richard Uhler74ee2992019-07-01 15:21:44 +0100410 synchronized (mLock) {
411 mRollbacks.clear();
Richard Uhler8d512ee2019-07-19 14:55:01 +0100412 mRollbacks.addAll(mRollbackStore.loadRollbacks());
Richard Uhler74ee2992019-07-01 15:21:44 +0100413 }
414 latch.countDown();
shafik6d61f5e2019-02-26 09:33:26 +0000415 });
Richard Uhler74ee2992019-07-01 15:21:44 +0100416
417 try {
418 latch.await();
419 } catch (InterruptedException ie) {
420 throw new IllegalStateException("RollbackManagerHandlerThread interrupted");
421 }
Richard Uhlere95d0552018-12-27 15:03:41 +0000422 }
423
424 @Override
425 public void expireRollbackForPackage(String packageName) {
426 mContext.enforceCallingOrSelfPermission(
Richard Uhler1fc10c12019-03-18 11:38:46 +0000427 Manifest.permission.TEST_MANAGE_ROLLBACKS,
Richard Uhlere95d0552018-12-27 15:03:41 +0000428 "expireRollbackForPackage");
Richard Uhlere95d0552018-12-27 15:03:41 +0000429 synchronized (mLock) {
Richard Uhler8d512ee2019-07-19 14:55:01 +0100430 Iterator<Rollback> iter = mRollbacks.iterator();
Richard Uhlere95d0552018-12-27 15:03:41 +0000431 while (iter.hasNext()) {
Richard Uhler8d512ee2019-07-19 14:55:01 +0100432 Rollback rollback = iter.next();
Oli Lan4af2f752019-09-27 10:39:32 +0100433 if (rollback.includesPackage(packageName)) {
434 iter.remove();
435 rollback.delete(mAppDataRollbackHelper);
Richard Uhlere95d0552018-12-27 15:03:41 +0000436 }
437 }
438 }
439 }
440
Richard Uhler798b8592019-06-07 14:04:43 +0100441 @Override
442 public void blockRollbackManager(long millis) {
443 mContext.enforceCallingOrSelfPermission(
444 Manifest.permission.TEST_MANAGE_ROLLBACKS,
445 "blockRollbackManager");
446 getHandler().post(() -> {
JW Wangfab29c62019-11-19 16:17:41 +0800447 mSleepDuration.addLast(millis);
448 });
449 }
450
JW Wang53e89c92019-11-28 19:53:45 +0800451 @WorkerThread
JW Wangfab29c62019-11-19 16:17:41 +0800452 private void queueSleepIfNeeded() {
453 if (mSleepDuration.size() == 0) {
454 return;
455 }
456 long millis = mSleepDuration.removeFirst();
457 if (millis <= 0) {
458 return;
459 }
460 getHandler().post(() -> {
Richard Uhler798b8592019-06-07 14:04:43 +0100461 try {
462 Thread.sleep(millis);
463 } catch (InterruptedException e) {
Richard Uhler74ee2992019-07-01 15:21:44 +0100464 throw new IllegalStateException("RollbackManagerHandlerThread interrupted");
Richard Uhler798b8592019-06-07 14:04:43 +0100465 }
466 });
467 }
468
Narayan Kamathc034fe92019-01-23 10:48:17 +0000469 void onUnlockUser(int userId) {
JW Wang12d0c3e2019-12-02 21:01:35 +0800470 if (LOCAL_LOGV) {
471 Slog.v(TAG, "onUnlockUser id=" + userId);
472 }
Gavin Corkeryf1154512019-09-05 11:48:55 +0100473 // In order to ensure that no package begins running while a backup or restore is taking
474 // place, onUnlockUser must remain blocked until all pending backups and restores have
475 // completed.
476 CountDownLatch latch = new CountDownLatch(1);
Narayan Kamathc034fe92019-01-23 10:48:17 +0000477 getHandler().post(() -> {
Richard Uhler8d512ee2019-07-19 14:55:01 +0100478 final List<Rollback> rollbacks;
Narayan Kamathc034fe92019-01-23 10:48:17 +0000479 synchronized (mLock) {
Richard Uhler6f8a33b2019-02-26 10:40:36 +0000480 rollbacks = new ArrayList<>(mRollbacks);
Narayan Kamathc034fe92019-01-23 10:48:17 +0000481 }
482
Oli Lan31f453f2019-09-11 09:58:39 +0100483 for (int i = 0; i < rollbacks.size(); i++) {
484 Rollback rollback = rollbacks.get(i);
Oli Lan4af2f752019-09-27 10:39:32 +0100485 rollback.commitPendingBackupAndRestoreForUser(userId, mAppDataRollbackHelper);
Narayan Kamathc034fe92019-01-23 10:48:17 +0000486 }
Oli Lan31f453f2019-09-11 09:58:39 +0100487
Gavin Corkeryf1154512019-09-05 11:48:55 +0100488 latch.countDown();
Oli Lan592cd9d2020-03-05 12:08:42 +0000489
490 destroyCeSnapshotsForExpiredRollbacks(userId);
Narayan Kamathc034fe92019-01-23 10:48:17 +0000491 });
Gavin Corkeryf1154512019-09-05 11:48:55 +0100492
493 try {
494 latch.await();
495 } catch (InterruptedException ie) {
496 throw new IllegalStateException("RollbackManagerHandlerThread interrupted");
497 }
Narayan Kamathc034fe92019-01-23 10:48:17 +0000498 }
499
JW Wang53e89c92019-11-28 19:53:45 +0800500 @WorkerThread
Oli Lan592cd9d2020-03-05 12:08:42 +0000501 private void destroyCeSnapshotsForExpiredRollbacks(int userId) {
502 int[] rollbackIds = new int[mRollbacks.size()];
503 for (int i = 0; i < rollbackIds.length; i++) {
504 rollbackIds[i] = mRollbacks.get(i).info.getRollbackId();
505 }
506 ApexManager.getInstance().destroyCeSnapshotsNotSpecified(userId, rollbackIds);
507 }
508
509 @WorkerThread
shafik0ad18b82019-01-24 16:27:24 +0000510 private void updateRollbackLifetimeDurationInMillis() {
Stanislav Zholnin6b85dac2019-03-07 12:16:04 +0000511 mRollbackLifetimeDurationInMillis = DeviceConfig.getLong(
Matt Pape12187ae2019-03-14 13:37:32 -0700512 DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
513 RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS,
Stanislav Zholnin6b85dac2019-03-07 12:16:04 +0000514 DEFAULT_ROLLBACK_LIFETIME_DURATION_MILLIS);
shafik15c511f2019-03-08 11:52:08 +0000515 if (mRollbackLifetimeDurationInMillis < 0) {
516 mRollbackLifetimeDurationInMillis = DEFAULT_ROLLBACK_LIFETIME_DURATION_MILLIS;
517 }
shafik0ad18b82019-01-24 16:27:24 +0000518 }
519
JW Wang53e89c92019-11-28 19:53:45 +0800520 @AnyThread
Richard Uhlerb2c5cac2019-02-05 16:14:35 +0000521 void onBootCompleted() {
JW Wangc63c1da2020-01-15 15:44:25 +0800522 DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
523 mExecutor, properties -> updateRollbackLifetimeDurationInMillis());
shafik0ad18b82019-01-24 16:27:24 +0000524
Richard Uhlerb2c5cac2019-02-05 16:14:35 +0000525 getHandler().post(() -> {
JW Wang3a850192020-01-15 15:30:49 +0800526 updateRollbackLifetimeDurationInMillis();
527 runExpiration();
528
Richard Uhler6f8a33b2019-02-26 10:40:36 +0000529 // Check to see if any rollback-enabled staged sessions or staged
530 // rollback sessions been applied.
Richard Uhler8d512ee2019-07-19 14:55:01 +0100531 List<Rollback> enabling = new ArrayList<>();
532 List<Rollback> restoreInProgress = new ArrayList<>();
Richard Uhler1924d6d2019-04-26 10:20:12 +0100533 Set<String> apexPackageNames = new HashSet<>();
Richard Uhlerb2c5cac2019-02-05 16:14:35 +0000534 synchronized (mLock) {
JW Wanga4ce4332019-10-29 21:26:03 +0800535 Iterator<Rollback> iter = mRollbacks.iterator();
536 while (iter.hasNext()) {
537 Rollback rollback = iter.next();
538 if (!rollback.isStaged()) {
539 // We only care about staged rollbacks here
540 continue;
541 }
542
543 PackageInstaller.SessionInfo session = mContext.getPackageManager()
544 .getPackageInstaller().getSessionInfo(rollback.getStagedSessionId());
545 if (session == null || session.isStagedSessionFailed()) {
546 iter.remove();
547 rollback.delete(mAppDataRollbackHelper);
548 continue;
549 }
550
551 if (session.isStagedSessionApplied()) {
Oli Lan4af2f752019-09-27 10:39:32 +0100552 if (rollback.isEnabling()) {
553 enabling.add(rollback);
554 } else if (rollback.isRestoreUserDataInProgress()) {
555 restoreInProgress.add(rollback);
Richard Uhler1924d6d2019-04-26 10:20:12 +0100556 }
Richard Uhlerb2c5cac2019-02-05 16:14:35 +0000557 }
JW Wanga4ce4332019-10-29 21:26:03 +0800558 apexPackageNames.addAll(rollback.getApexPackageNames());
Richard Uhlerb2c5cac2019-02-05 16:14:35 +0000559 }
560 }
561
Richard Uhler8d512ee2019-07-19 14:55:01 +0100562 for (Rollback rollback : enabling) {
JW Wanga4ce4332019-10-29 21:26:03 +0800563 makeRollbackAvailable(rollback);
Richard Uhlerb2c5cac2019-02-05 16:14:35 +0000564 }
Richard Uhler6f8a33b2019-02-26 10:40:36 +0000565
Richard Uhler8d512ee2019-07-19 14:55:01 +0100566 for (Rollback rollback : restoreInProgress) {
JW Wanga4ce4332019-10-29 21:26:03 +0800567 rollback.setRestoreUserDataInProgress(false);
Richard Uhler6f8a33b2019-02-26 10:40:36 +0000568 }
Zimuzo841c4942019-03-04 12:31:48 +0000569
Richard Uhler1924d6d2019-04-26 10:20:12 +0100570 for (String apexPackageName : apexPackageNames) {
571 // We will not recieve notifications when an apex is updated,
572 // so check now in case any rollbacks ought to be expired. The
573 // onPackagedReplace function is safe to call if the package
574 // hasn't actually been updated.
575 onPackageReplaced(apexPackageName);
576 }
Oli Lan0bf44862019-08-29 14:25:38 +0100577
578 synchronized (mLock) {
579 mOrphanedApkSessionIds.clear();
580 }
581
shafikc5805fb92019-04-29 20:08:07 +0100582 mPackageHealthObserver.onBootCompletedAsync();
Richard Uhlerb2c5cac2019-02-05 16:14:35 +0000583 });
584 }
585
Richard Uhlere95d0552018-12-27 15:03:41 +0000586 /**
Richard Uhlere95d0552018-12-27 15:03:41 +0000587 * Called when a package has been replaced with a different version.
588 * Removes all backups for the package not matching the currently
589 * installed package version.
590 */
JW Wang53e89c92019-11-28 19:53:45 +0800591 @WorkerThread
Richard Uhlere95d0552018-12-27 15:03:41 +0000592 private void onPackageReplaced(String packageName) {
593 // TODO: Could this end up incorrectly deleting a rollback for a
594 // package that is about to be installed?
Oli Lan3143ee32019-09-18 17:07:21 +0100595 long installedVersion = getInstalledPackageVersion(packageName);
Richard Uhlere95d0552018-12-27 15:03:41 +0000596
597 synchronized (mLock) {
Richard Uhler8d512ee2019-07-19 14:55:01 +0100598 Iterator<Rollback> iter = mRollbacks.iterator();
Richard Uhlere95d0552018-12-27 15:03:41 +0000599 while (iter.hasNext()) {
Richard Uhler8d512ee2019-07-19 14:55:01 +0100600 Rollback rollback = iter.next();
Oli Lan4af2f752019-09-27 10:39:32 +0100601 // TODO: Should we remove rollbacks in the ENABLING state here?
602 if ((rollback.isEnabling() || rollback.isAvailable())
603 && rollback.includesPackageWithDifferentVersion(packageName,
604 installedVersion)) {
605 iter.remove();
606 rollback.delete(mAppDataRollbackHelper);
Richard Uhlere95d0552018-12-27 15:03:41 +0000607 }
608 }
609 }
610 }
611
612 /**
613 * Called when a package has been completely removed from the device.
614 * Removes all backups and rollback history for the given package.
615 */
JW Wang53e89c92019-11-28 19:53:45 +0800616 @WorkerThread
Richard Uhlere95d0552018-12-27 15:03:41 +0000617 private void onPackageFullyRemoved(String packageName) {
618 expireRollbackForPackage(packageName);
Richard Uhlere95d0552018-12-27 15:03:41 +0000619 }
620
621 /**
622 * Notifies an IntentSender of failure.
623 *
624 * @param statusReceiver where to send the failure
Richard Uhler2a48c292019-01-28 17:33:48 +0000625 * @param status the RollbackManager.STATUS_* code with the failure.
Richard Uhlere95d0552018-12-27 15:03:41 +0000626 * @param message the failure message.
627 */
JW Wang53e89c92019-11-28 19:53:45 +0800628 @AnyThread
Oli Lan7363a622019-09-13 10:06:12 +0100629 static void sendFailure(Context context, IntentSender statusReceiver,
630 @RollbackManager.Status int status, String message) {
shafikbb771fb2019-06-05 14:59:57 +0100631 Slog.e(TAG, message);
Richard Uhlere95d0552018-12-27 15:03:41 +0000632 try {
Richard Uhlere95d0552018-12-27 15:03:41 +0000633 final Intent fillIn = new Intent();
Richard Uhler2a48c292019-01-28 17:33:48 +0000634 fillIn.putExtra(RollbackManager.EXTRA_STATUS, status);
635 fillIn.putExtra(RollbackManager.EXTRA_STATUS_MESSAGE, message);
Oli Lan7363a622019-09-13 10:06:12 +0100636 statusReceiver.sendIntent(context, 0, fillIn, null, null);
Richard Uhlere95d0552018-12-27 15:03:41 +0000637 } catch (IntentSender.SendIntentException e) {
638 // Nowhere to send the result back to, so don't bother.
639 }
640 }
641
642 // Check to see if anything needs expiration, and if so, expire it.
643 // Schedules future expiration as appropriate.
JW Wang53e89c92019-11-28 19:53:45 +0800644 @WorkerThread
Richard Uhlere95d0552018-12-27 15:03:41 +0000645 private void runExpiration() {
646 Instant now = Instant.now();
647 Instant oldest = null;
648 synchronized (mLock) {
Richard Uhler8d512ee2019-07-19 14:55:01 +0100649 Iterator<Rollback> iter = mRollbacks.iterator();
Richard Uhlere95d0552018-12-27 15:03:41 +0000650 while (iter.hasNext()) {
Richard Uhler8d512ee2019-07-19 14:55:01 +0100651 Rollback rollback = iter.next();
Oli Lan4af2f752019-09-27 10:39:32 +0100652 if (!rollback.isAvailable()) {
653 continue;
654 }
655 Instant rollbackTimestamp = rollback.getTimestamp();
656 if (!now.isBefore(
657 rollbackTimestamp
658 .plusMillis(mRollbackLifetimeDurationInMillis))) {
JW Wang12d0c3e2019-12-02 21:01:35 +0800659 if (LOCAL_LOGV) {
660 Slog.v(TAG, "runExpiration id=" + rollback.info.getRollbackId());
661 }
Oli Lan4af2f752019-09-27 10:39:32 +0100662 iter.remove();
663 rollback.delete(mAppDataRollbackHelper);
664 } else if (oldest == null || oldest.isAfter(rollbackTimestamp)) {
665 oldest = rollbackTimestamp;
Richard Uhlere95d0552018-12-27 15:03:41 +0000666 }
667 }
668 }
669
670 if (oldest != null) {
shafik0ad18b82019-01-24 16:27:24 +0000671 scheduleExpiration(now.until(oldest.plusMillis(mRollbackLifetimeDurationInMillis),
Richard Uhlere95d0552018-12-27 15:03:41 +0000672 ChronoUnit.MILLIS));
673 }
674 }
675
676 /**
677 * Schedules an expiration check to be run after the given duration in
678 * milliseconds has gone by.
679 */
JW Wang53e89c92019-11-28 19:53:45 +0800680 @AnyThread
Richard Uhlere95d0552018-12-27 15:03:41 +0000681 private void scheduleExpiration(long duration) {
682 getHandler().postDelayed(() -> runExpiration(), duration);
683 }
684
JW Wang53e89c92019-11-28 19:53:45 +0800685 @AnyThread
Richard Uhlere95d0552018-12-27 15:03:41 +0000686 private Handler getHandler() {
687 return mHandlerThread.getThreadHandler();
688 }
689
JW Wang53e89c92019-11-28 19:53:45 +0800690 @AnyThread
Richard Uhler82913b72019-04-01 13:02:31 +0100691 private Context getContextAsUser(UserHandle user) {
692 try {
693 return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
694 } catch (PackageManager.NameNotFoundException e) {
695 return null;
696 }
697 }
698
Richard Uhlere95d0552018-12-27 15:03:41 +0000699 /**
700 * Called via broadcast by the package manager when a package is being
701 * staged for install with rollback enabled. Called before the package has
702 * been installed.
703 *
JW Wang298239b2020-02-17 17:08:02 +0800704 * @param sessionId the id of the install session
Richard Uhlere95d0552018-12-27 15:03:41 +0000705 * @return true if enabling the rollback succeeds, false otherwise.
706 */
JW Wang53e89c92019-11-28 19:53:45 +0800707 @WorkerThread
JW Wang298239b2020-02-17 17:08:02 +0800708 private boolean enableRollback(int sessionId) {
JW Wang12d0c3e2019-12-02 21:01:35 +0800709 if (LOCAL_LOGV) {
JW Wang298239b2020-02-17 17:08:02 +0800710 Slog.v(TAG, "enableRollback sessionId=" + sessionId);
JW Wang12d0c3e2019-12-02 21:01:35 +0800711 }
Richard Uhlere95d0552018-12-27 15:03:41 +0000712
JW Wang635382e2020-02-17 16:30:52 +0800713 PackageInstaller installer = mContext.getPackageManager().getPackageInstaller();
714 PackageInstaller.SessionInfo packageSession = installer.getSessionInfo(sessionId);
715 if (packageSession == null) {
716 Slog.e(TAG, "Unable to find session for enabled rollback.");
Richard Uhler82913b72019-04-01 13:02:31 +0100717 return false;
718 }
719
JW Wang635382e2020-02-17 16:30:52 +0800720 PackageInstaller.SessionInfo parentSession = packageSession.hasParentSessionId()
721 ? installer.getSessionInfo(packageSession.getParentSessionId()) : packageSession;
722 if (parentSession == null) {
723 Slog.e(TAG, "Unable to find parent session for enabled rollback.");
Richard Uhler2d7c7f0d2019-01-04 09:18:21 +0000724 return false;
725 }
726
Richard Uhlerac0d0f92019-02-05 15:53:47 +0000727 // Check to see if this is the apk session for a staged session with
728 // rollback enabled.
Richard Uhlerac0d0f92019-02-05 15:53:47 +0000729 synchronized (mLock) {
Richard Uhler6f8a33b2019-02-26 10:40:36 +0000730 for (int i = 0; i < mRollbacks.size(); ++i) {
Richard Uhler8d512ee2019-07-19 14:55:01 +0100731 Rollback rollback = mRollbacks.get(i);
Oli Lan4af2f752019-09-27 10:39:32 +0100732 if (rollback.getApkSessionId() == parentSession.getSessionId()) {
733 // This is the apk session for a staged session with rollback enabled. We do
734 // not need to create a new rollback for this session.
735 return true;
Richard Uhlerac0d0f92019-02-05 15:53:47 +0000736 }
737 }
Richard Uhlerac0d0f92019-02-05 15:53:47 +0000738 }
739
Oli Lan0bf44862019-08-29 14:25:38 +0100740 // Check to see if this is the apk session for a staged session for which rollback was
741 // cancelled.
742 synchronized (mLock) {
743 if (mOrphanedApkSessionIds.indexOf(parentSession.getSessionId()) != -1) {
744 Slog.w(TAG, "Not enabling rollback for apk as no matching staged session "
745 + "rollback exists");
746 return false;
747 }
748 }
749
JW Wangab3064c2020-01-10 14:12:19 +0800750 Rollback newRollback;
Richard Uhler47569702019-05-02 12:36:39 +0100751 synchronized (mLock) {
JW Wang06650e72020-02-07 16:03:35 +0800752 // See if we already have a Rollback that contains this package
753 // session. If not, create a new Rollback for the parent session
Richard Uhler47569702019-05-02 12:36:39 +0100754 // that we will use for all the packages in the session.
JW Wang06650e72020-02-07 16:03:35 +0800755 newRollback = getRollbackForSessionLocked(packageSession.getSessionId());
Richard Uhler47569702019-05-02 12:36:39 +0100756 if (newRollback == null) {
757 newRollback = createNewRollbackLocked(parentSession);
Richard Uhler47569702019-05-02 12:36:39 +0100758 }
759 }
760
JW Wangab3064c2020-01-10 14:12:19 +0800761 return enableRollbackForPackageSession(newRollback, packageSession);
Richard Uhlerf0bdca52019-01-31 16:43:59 +0000762 }
763
764 /**
765 * Do code and userdata backups to enable rollback of the given session.
766 * In case of multiPackage sessions, <code>session</code> should be one of
767 * the child sessions, not the parent session.
Richard Uhler47569702019-05-02 12:36:39 +0100768 *
769 * @return true on success, false on failure.
Richard Uhlerf0bdca52019-01-31 16:43:59 +0000770 */
JW Wang53e89c92019-11-28 19:53:45 +0800771 @WorkerThread
Richard Uhler8d512ee2019-07-19 14:55:01 +0100772 private boolean enableRollbackForPackageSession(Rollback rollback,
Oli Lan48f3cf42019-08-09 10:25:49 +0100773 PackageInstaller.SessionInfo session) {
Richard Uhlerf0bdca52019-01-31 16:43:59 +0000774 // TODO: Don't attempt to enable rollback for split installs.
775 final int installFlags = session.installFlags;
776 if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) == 0) {
shafikbb771fb2019-06-05 14:59:57 +0100777 Slog.e(TAG, "Rollback is not enabled.");
Richard Uhlerf0bdca52019-01-31 16:43:59 +0000778 return false;
779 }
780 if ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
shafikbb771fb2019-06-05 14:59:57 +0100781 Slog.e(TAG, "Rollbacks not supported for instant app install");
Richard Uhlerf0bdca52019-01-31 16:43:59 +0000782 return false;
783 }
784
Richard Uhlerfcad49a2019-03-13 10:18:46 +0000785 if (session.resolvedBaseCodePath == null) {
shafikbb771fb2019-06-05 14:59:57 +0100786 Slog.e(TAG, "Session code path has not been resolved.");
Richard Uhlerfcad49a2019-03-13 10:18:46 +0000787 return false;
788 }
789
Richard Uhlerf0bdca52019-01-31 16:43:59 +0000790 // Get information about the package to be installed.
Oli Lan856391f2019-09-25 16:08:01 +0100791 PackageParser.PackageLite newPackage;
Richard Uhlerf0bdca52019-01-31 16:43:59 +0000792 try {
793 newPackage = PackageParser.parsePackageLite(new File(session.resolvedBaseCodePath), 0);
794 } catch (PackageParser.PackageParserException e) {
shafikbb771fb2019-06-05 14:59:57 +0100795 Slog.e(TAG, "Unable to parse new package", e);
Richard Uhlerf0bdca52019-01-31 16:43:59 +0000796 return false;
797 }
798
799 String packageName = newPackage.packageName;
shafikbb771fb2019-06-05 14:59:57 +0100800 Slog.i(TAG, "Enabling rollback for install of " + packageName
Narayan Kamathfcd4a042019-02-01 14:16:37 +0000801 + ", session:" + session.sessionId);
Richard Uhlerf0bdca52019-01-31 16:43:59 +0000802
Richard Uhler1fc10c12019-03-18 11:38:46 +0000803 String installerPackageName = session.getInstallerPackageName();
804 if (!enableRollbackAllowed(installerPackageName, packageName)) {
shafikbb771fb2019-06-05 14:59:57 +0100805 Slog.e(TAG, "Installer " + installerPackageName
Richard Uhler1fc10c12019-03-18 11:38:46 +0000806 + " is not allowed to enable rollback on " + packageName);
807 return false;
808 }
809
Narayan Kamathfcd4a042019-02-01 14:16:37 +0000810 final boolean isApex = ((installFlags & PackageManager.INSTALL_APEX) != 0);
Richard Uhlere95d0552018-12-27 15:03:41 +0000811
812 // Get information about the currently installed package.
Richard Uhler1fc10c12019-03-18 11:38:46 +0000813 final PackageInfo pkgInfo;
Richard Uhler1f571c62019-01-31 15:16:46 +0000814 try {
Richard Uhler82913b72019-04-01 13:02:31 +0100815 pkgInfo = getPackageInfo(packageName);
Richard Uhler1f571c62019-01-31 15:16:46 +0000816 } catch (PackageManager.NameNotFoundException e) {
Richard Uhlere95d0552018-12-27 15:03:41 +0000817 // TODO: Support rolling back fresh package installs rather than
818 // fail here. Test this case.
shafikbb771fb2019-06-05 14:59:57 +0100819 Slog.e(TAG, packageName + " is not installed");
Richard Uhlere95d0552018-12-27 15:03:41 +0000820 return false;
821 }
Richard Uhlere95d0552018-12-27 15:03:41 +0000822
Mohammad Samiul Islam3fcecfc2019-12-20 17:46:01 +0000823 if (isApex) {
824 // Check if this apex contains apks inside it. If true, then they should be added as
825 // a RollbackPackageInfo into this rollback
826 final PackageManagerInternal pmi = LocalServices.getService(
827 PackageManagerInternal.class);
828 List<String> apksInApex = pmi.getApksInApex(packageName);
829 for (String apkInApex : apksInApex) {
830 // Get information about the currently installed package.
831 final PackageInfo apkPkgInfo;
832 try {
833 apkPkgInfo = getPackageInfo(apkInApex);
834 } catch (PackageManager.NameNotFoundException e) {
835 // TODO: Support rolling back fresh package installs rather than
836 // fail here. Test this case.
837 Slog.e(TAG, apkInApex + " is not installed");
838 return false;
839 }
JW Wang7fcc7302020-02-12 11:30:18 +0800840 if (!rollback.enableForPackageInApex(
841 apkInApex, apkPkgInfo.getLongVersionCode(), session.rollbackDataPolicy)) {
842 return false;
843 }
Mohammad Samiul Islam3fcecfc2019-12-20 17:46:01 +0000844 }
845 }
JW Wang7fcc7302020-02-12 11:30:18 +0800846
847 /**
848 * The order is important here! Always enable the embedded apk-in-apex (if any) before
849 * enabling the embedding apex. Otherwise the rollback object might be in an inconsistent
850 * state where an embedding apex is successfully enabled while one of its embedded
851 * apk-in-apex failed. Note {@link Rollback#allPackagesEnabled()} won't behave correctly if
852 * a rollback object is inconsistent because it doesn't count apk-in-apex.
853 */
854 ApplicationInfo appInfo = pkgInfo.applicationInfo;
855 return rollback.enableForPackage(packageName, newPackage.versionCode,
856 pkgInfo.getLongVersionCode(), isApex, appInfo.sourceDir,
857 appInfo.splitSourceDirs, session.rollbackDataPolicy);
Richard Uhlere95d0552018-12-27 15:03:41 +0000858 }
859
Narayan Kamath869f7062019-01-10 12:24:15 +0000860 @Override
Gavin Corkeryab5ee412019-05-29 15:33:35 +0100861 public void snapshotAndRestoreUserData(String packageName, int[] userIds, int appId,
862 long ceDataInode, String seInfo, int token) {
Narayan Kamath869f7062019-01-10 12:24:15 +0000863 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
Gavin Corkeryab5ee412019-05-29 15:33:35 +0100864 throw new SecurityException(
865 "snapshotAndRestoreUserData may only be called by the system.");
Narayan Kamath869f7062019-01-10 12:24:15 +0000866 }
867
868 getHandler().post(() -> {
Oli Lan48f3cf42019-08-09 10:25:49 +0100869 snapshotUserDataInternal(packageName, userIds);
Oli Lan856391f2019-09-25 16:08:01 +0100870 restoreUserDataInternal(packageName, userIds, appId, seInfo);
Mohammad Samiul Islam3fcecfc2019-12-20 17:46:01 +0000871 // When this method is called as part of the install flow, a positive token number is
872 // passed to it. Need to notify the PackageManager when we are done.
873 if (token > 0) {
874 final PackageManagerInternal pmi = LocalServices.getService(
875 PackageManagerInternal.class);
876 pmi.finishPackageInstall(token, false);
877 }
Narayan Kamath869f7062019-01-10 12:24:15 +0000878 });
879 }
880
JW Wang53e89c92019-11-28 19:53:45 +0800881 @WorkerThread
Oli Lan48f3cf42019-08-09 10:25:49 +0100882 private void snapshotUserDataInternal(String packageName, int[] userIds) {
JW Wang12d0c3e2019-12-02 21:01:35 +0800883 if (LOCAL_LOGV) {
884 Slog.v(TAG, "snapshotUserData pkg=" + packageName
885 + " users=" + Arrays.toString(userIds));
886 }
Gavin Corkeryab5ee412019-05-29 15:33:35 +0100887 synchronized (mLock) {
Gavin Corkeryab5ee412019-05-29 15:33:35 +0100888 for (int i = 0; i < mRollbacks.size(); i++) {
Richard Uhler8d512ee2019-07-19 14:55:01 +0100889 Rollback rollback = mRollbacks.get(i);
Oli Lan4af2f752019-09-27 10:39:32 +0100890 rollback.snapshotUserData(packageName, userIds, mAppDataRollbackHelper);
Gavin Corkeryab5ee412019-05-29 15:33:35 +0100891 }
Gavin Corkeryab5ee412019-05-29 15:33:35 +0100892 }
893 }
894
JW Wang53e89c92019-11-28 19:53:45 +0800895 @WorkerThread
Oli Lan856391f2019-09-25 16:08:01 +0100896 private void restoreUserDataInternal(
897 String packageName, int[] userIds, int appId, String seInfo) {
JW Wang12d0c3e2019-12-02 21:01:35 +0800898 if (LOCAL_LOGV) {
899 Slog.v(TAG, "restoreUserData pkg=" + packageName
900 + " users=" + Arrays.toString(userIds));
901 }
Richard Uhler6f8a33b2019-02-26 10:40:36 +0000902 synchronized (mLock) {
Richard Uhler6f8a33b2019-02-26 10:40:36 +0000903 for (int i = 0; i < mRollbacks.size(); ++i) {
Oli Lan856391f2019-09-25 16:08:01 +0100904 Rollback rollback = mRollbacks.get(i);
Oli Lan4af2f752019-09-27 10:39:32 +0100905 if (rollback.restoreUserDataForPackageIfInProgress(
906 packageName, userIds, appId, seInfo, mAppDataRollbackHelper)) {
907 return;
Richard Uhler6f8a33b2019-02-26 10:40:36 +0000908 }
909 }
910 }
Richard Uhler38fab3f2019-02-22 16:53:10 +0000911 }
912
Narayan Kamathfcd4a042019-02-01 14:16:37 +0000913 @Override
Oli Lanc72b0bb2019-12-02 14:03:55 +0000914 public int notifyStagedSession(int sessionId) {
shafik3be41a92019-03-25 14:10:32 +0000915 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
916 throw new SecurityException("notifyStagedSession may only be called by the system.");
917 }
Oli Lanc72b0bb2019-12-02 14:03:55 +0000918 final LinkedBlockingQueue<Integer> result = new LinkedBlockingQueue<>();
Narayan Kamathfcd4a042019-02-01 14:16:37 +0000919
920 // NOTE: We post this runnable on the RollbackManager's binder thread because we'd prefer
921 // to preserve the invariant that all operations that modify state happen there.
922 getHandler().post(() -> {
923 PackageInstaller installer = mContext.getPackageManager().getPackageInstaller();
924
925 final PackageInstaller.SessionInfo session = installer.getSessionInfo(sessionId);
926 if (session == null) {
shafikbb771fb2019-06-05 14:59:57 +0100927 Slog.e(TAG, "No matching install session for: " + sessionId);
Oli Lanc72b0bb2019-12-02 14:03:55 +0000928 result.offer(-1);
Narayan Kamathfcd4a042019-02-01 14:16:37 +0000929 return;
930 }
931
JW Wangab3064c2020-01-10 14:12:19 +0800932 Rollback newRollback;
Richard Uhler47569702019-05-02 12:36:39 +0100933 synchronized (mLock) {
934 newRollback = createNewRollbackLocked(session);
935 }
936
Narayan Kamathfcd4a042019-02-01 14:16:37 +0000937 if (!session.isMultiPackage()) {
JW Wangab3064c2020-01-10 14:12:19 +0800938 if (!enableRollbackForPackageSession(newRollback, session)) {
shafikbb771fb2019-06-05 14:59:57 +0100939 Slog.e(TAG, "Unable to enable rollback for session: " + sessionId);
Narayan Kamathfcd4a042019-02-01 14:16:37 +0000940 }
941 } else {
942 for (int childSessionId : session.getChildSessionIds()) {
943 final PackageInstaller.SessionInfo childSession =
944 installer.getSessionInfo(childSessionId);
945 if (childSession == null) {
shafikbb771fb2019-06-05 14:59:57 +0100946 Slog.e(TAG, "No matching child install session for: " + childSessionId);
JW Wangb3ea9a62020-02-12 10:53:28 +0800947 break;
Narayan Kamathfcd4a042019-02-01 14:16:37 +0000948 }
JW Wangab3064c2020-01-10 14:12:19 +0800949 if (!enableRollbackForPackageSession(newRollback, childSession)) {
shafikbb771fb2019-06-05 14:59:57 +0100950 Slog.e(TAG, "Unable to enable rollback for session: " + sessionId);
JW Wangb3ea9a62020-02-12 10:53:28 +0800951 break;
Narayan Kamathfcd4a042019-02-01 14:16:37 +0000952 }
953 }
954 }
955
JW Wang38a56562020-02-11 15:37:19 +0800956 if (!completeEnableRollback(newRollback)) {
Oli Lanc72b0bb2019-12-02 14:03:55 +0000957 result.offer(-1);
958 } else {
JW Wang38a56562020-02-11 15:37:19 +0800959 result.offer(newRollback.info.getRollbackId());
Oli Lanc72b0bb2019-12-02 14:03:55 +0000960 }
Narayan Kamathfcd4a042019-02-01 14:16:37 +0000961 });
962
963 try {
964 return result.take();
965 } catch (InterruptedException ie) {
shafikbb771fb2019-06-05 14:59:57 +0100966 Slog.e(TAG, "Interrupted while waiting for notifyStagedSession response");
Oli Lanc72b0bb2019-12-02 14:03:55 +0000967 return -1;
Narayan Kamathfcd4a042019-02-01 14:16:37 +0000968 }
969 }
970
Richard Uhler6fa7d132019-02-05 13:55:11 +0000971 @Override
972 public void notifyStagedApkSession(int originalSessionId, int apkSessionId) {
shafik3be41a92019-03-25 14:10:32 +0000973 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
974 throw new SecurityException("notifyStagedApkSession may only be called by the system.");
975 }
Richard Uhlerba13ab22019-02-05 15:27:12 +0000976 getHandler().post(() -> {
Richard Uhler8d512ee2019-07-19 14:55:01 +0100977 Rollback rollback = null;
Richard Uhlerba13ab22019-02-05 15:27:12 +0000978 synchronized (mLock) {
Richard Uhler6f8a33b2019-02-26 10:40:36 +0000979 for (int i = 0; i < mRollbacks.size(); ++i) {
Richard Uhler8d512ee2019-07-19 14:55:01 +0100980 Rollback candidate = mRollbacks.get(i);
Oli Land0c30412019-09-09 18:21:54 +0100981 if (candidate.getStagedSessionId() == originalSessionId) {
Richard Uhler8d512ee2019-07-19 14:55:01 +0100982 rollback = candidate;
Richard Uhlerba13ab22019-02-05 15:27:12 +0000983 break;
984 }
985 }
Oli Lan0bf44862019-08-29 14:25:38 +0100986 if (rollback == null) {
987 // Did not find rollback matching originalSessionId.
988 Slog.e(TAG, "notifyStagedApkSession did not find rollback for session "
989 + originalSessionId
990 + ". Adding orphaned apk session " + apkSessionId);
991 mOrphanedApkSessionIds.add(apkSessionId);
992 }
Richard Uhlerba13ab22019-02-05 15:27:12 +0000993 }
994
Richard Uhler8d512ee2019-07-19 14:55:01 +0100995 if (rollback != null) {
Oli Lan4af2f752019-09-27 10:39:32 +0100996 rollback.setApkSessionId(apkSessionId);
Richard Uhlerba13ab22019-02-05 15:27:12 +0000997 }
998 });
Richard Uhler6fa7d132019-02-05 13:55:11 +0000999 }
1000
Richard Uhlere95d0552018-12-27 15:03:41 +00001001 /**
Richard Uhler1fc10c12019-03-18 11:38:46 +00001002 * Returns true if the installer is allowed to enable rollback for the
1003 * given named package, false otherwise.
1004 */
JW Wang53e89c92019-11-28 19:53:45 +08001005 @AnyThread
Richard Uhler1fc10c12019-03-18 11:38:46 +00001006 private boolean enableRollbackAllowed(String installerPackageName, String packageName) {
1007 if (installerPackageName == null) {
1008 return false;
1009 }
1010
1011 PackageManager pm = mContext.getPackageManager();
1012 boolean manageRollbacksGranted = pm.checkPermission(
1013 Manifest.permission.MANAGE_ROLLBACKS,
1014 installerPackageName) == PackageManager.PERMISSION_GRANTED;
1015
1016 boolean testManageRollbacksGranted = pm.checkPermission(
1017 Manifest.permission.TEST_MANAGE_ROLLBACKS,
1018 installerPackageName) == PackageManager.PERMISSION_GRANTED;
1019
1020 // For now only allow rollbacks for modules or for testing.
JW Wang9b51b732019-12-11 17:14:15 +08001021 return (isRollbackWhitelisted(packageName) && manageRollbacksGranted)
Richard Uhler1fc10c12019-03-18 11:38:46 +00001022 || testManageRollbacksGranted;
1023 }
1024
1025 /**
JW Wang9b51b732019-12-11 17:14:15 +08001026 * Returns true is this package is eligible for enabling rollback.
1027 */
JW Wang53e89c92019-11-28 19:53:45 +08001028 @AnyThread
JW Wang9b51b732019-12-11 17:14:15 +08001029 private boolean isRollbackWhitelisted(String packageName) {
1030 // TODO: Remove #isModule when the white list is ready.
1031 return SystemConfig.getInstance().getRollbackWhitelistedPackages().contains(packageName)
1032 || isModule(packageName);
1033 }
1034 /**
Richard Uhler1fc10c12019-03-18 11:38:46 +00001035 * Returns true if the package name is the name of a module.
1036 */
JW Wang53e89c92019-11-28 19:53:45 +08001037 @AnyThread
Richard Uhler1fc10c12019-03-18 11:38:46 +00001038 private boolean isModule(String packageName) {
1039 PackageManager pm = mContext.getPackageManager();
1040 final ModuleInfo moduleInfo;
1041 try {
1042 moduleInfo = pm.getModuleInfo(packageName, 0);
1043 } catch (PackageManager.NameNotFoundException e) {
1044 return false;
1045 }
1046
1047 return moduleInfo != null;
1048 }
1049
1050 /**
Richard Uhlere95d0552018-12-27 15:03:41 +00001051 * Gets the version of the package currently installed.
Oli Lan3143ee32019-09-18 17:07:21 +01001052 * Returns -1 if the package is not currently installed.
Richard Uhlere95d0552018-12-27 15:03:41 +00001053 */
JW Wang53e89c92019-11-28 19:53:45 +08001054 @AnyThread
Oli Lan3143ee32019-09-18 17:07:21 +01001055 private long getInstalledPackageVersion(String packageName) {
Oli Lan856391f2019-09-25 16:08:01 +01001056 PackageInfo pkgInfo;
Richard Uhlere95d0552018-12-27 15:03:41 +00001057 try {
Richard Uhler82913b72019-04-01 13:02:31 +01001058 pkgInfo = getPackageInfo(packageName);
Richard Uhlere95d0552018-12-27 15:03:41 +00001059 } catch (PackageManager.NameNotFoundException e) {
Oli Lan3143ee32019-09-18 17:07:21 +01001060 return -1;
Richard Uhlere95d0552018-12-27 15:03:41 +00001061 }
1062
Oli Lan3143ee32019-09-18 17:07:21 +01001063 return pkgInfo.getLongVersionCode();
Richard Uhlera7e9b2d2019-01-22 17:20:58 +00001064 }
1065
Richard Uhler82913b72019-04-01 13:02:31 +01001066 /**
Oli Lan856391f2019-09-25 16:08:01 +01001067 * Gets PackageInfo for the given package. Matches any user and apex.
1068 *
1069 * @throws PackageManager.NameNotFoundException if no such package is installed.
Richard Uhler82913b72019-04-01 13:02:31 +01001070 */
JW Wang53e89c92019-11-28 19:53:45 +08001071 @AnyThread
Richard Uhler82913b72019-04-01 13:02:31 +01001072 private PackageInfo getPackageInfo(String packageName)
1073 throws PackageManager.NameNotFoundException {
1074 PackageManager pm = mContext.getPackageManager();
1075 try {
1076 // The MATCH_ANY_USER flag doesn't mix well with the MATCH_APEX
1077 // flag, so make two separate attempts to get the package info.
1078 // We don't need both flags at the same time because we assume
1079 // apex files are always installed for all users.
1080 return pm.getPackageInfo(packageName, PackageManager.MATCH_ANY_USER);
1081 } catch (PackageManager.NameNotFoundException e) {
1082 return pm.getPackageInfo(packageName, PackageManager.MATCH_APEX);
1083 }
1084 }
1085
JW Wang53e89c92019-11-28 19:53:45 +08001086 @WorkerThread
Richard Uhler2d7c7f0d2019-01-04 09:18:21 +00001087 private class SessionCallback extends PackageInstaller.SessionCallback {
1088
1089 @Override
1090 public void onCreated(int sessionId) { }
1091
1092 @Override
1093 public void onBadgingChanged(int sessionId) { }
1094
1095 @Override
1096 public void onActiveChanged(int sessionId, boolean active) { }
1097
1098 @Override
1099 public void onProgressChanged(int sessionId, float progress) { }
1100
1101 @Override
1102 public void onFinished(int sessionId, boolean success) {
JW Wang12d0c3e2019-12-02 21:01:35 +08001103 if (LOCAL_LOGV) {
1104 Slog.v(TAG, "SessionCallback.onFinished id=" + sessionId + " success=" + success);
1105 }
Richard Uhler47569702019-05-02 12:36:39 +01001106
JW Wang3fa0ce92019-12-20 14:34:40 +08001107 if (success) {
JW Wang7e5eaad2020-02-07 16:25:53 +08001108 Rollback rollback;
JW Wang3fa0ce92019-12-20 14:34:40 +08001109 synchronized (mLock) {
JW Wang7e5eaad2020-02-07 16:25:53 +08001110 rollback = getRollbackForSessionLocked(sessionId);
Richard Uhler47569702019-05-02 12:36:39 +01001111 }
JW Wangb18925b2020-02-11 16:20:06 +08001112 if (rollback != null && !rollback.isStaged() && rollback.isEnabling()
1113 && rollback.notifySessionWithSuccess()
1114 && completeEnableRollback(rollback)) {
JW Wang7e5eaad2020-02-07 16:25:53 +08001115 makeRollbackAvailable(rollback);
JW Wang3fa0ce92019-12-20 14:34:40 +08001116 }
1117 } else {
JW Wang1ac3d112020-02-07 15:52:36 +08001118 synchronized (mLock) {
1119 Rollback rollback = getRollbackForSessionLocked(sessionId);
1120 if (rollback != null && rollback.isEnabling()) {
1121 Slog.w(TAG, "Delete rollback id=" + rollback.info.getRollbackId()
1122 + " for failed session id=" + sessionId);
1123 mRollbacks.remove(rollback);
1124 rollback.delete(mAppDataRollbackHelper);
1125 }
1126 }
Richard Uhler2d7c7f0d2019-01-04 09:18:21 +00001127 }
Narayan Kamathfcd4a042019-02-01 14:16:37 +00001128 }
1129 }
Richard Uhler2d7c7f0d2019-01-04 09:18:21 +00001130
Richard Uhler6f8a33b2019-02-26 10:40:36 +00001131 /**
JW Wangb18925b2020-02-11 16:20:06 +08001132 * Persist a rollback as enable-completed. It does not make the rollback available yet.
1133 * This rollback will be deleted and removed from {@link #mRollbacks} should any error happens.
Oli Lan8c0084d2019-09-11 13:38:43 +01001134 *
JW Wang38a56562020-02-11 15:37:19 +08001135 * @return {code true} if {code rollback} is successfully enable-completed,
1136 * or {code false} otherwise.
Richard Uhler6f8a33b2019-02-26 10:40:36 +00001137 */
JW Wang53e89c92019-11-28 19:53:45 +08001138 @WorkerThread
JW Wang38a56562020-02-11 15:37:19 +08001139 private boolean completeEnableRollback(Rollback rollback) {
JW Wang12d0c3e2019-12-02 21:01:35 +08001140 if (LOCAL_LOGV) {
JW Wang6a70aaf2019-12-26 15:02:19 +08001141 Slog.v(TAG, "completeEnableRollback id=" + rollback.info.getRollbackId());
Oli Lan8c0084d2019-09-11 13:38:43 +01001142 }
Oli Lan4af2f752019-09-27 10:39:32 +01001143
Mohammad Samiul Islam3ffedc42020-01-06 13:53:16 +00001144 // We are checking if number of packages (excluding apk-in-apex) we enabled for rollback is
1145 // equal to the number of sessions we are installing, to ensure we didn't skip enabling
1146 // of any sessions. If we successfully enable an apex, then we can assume we enabled
1147 // rollback for the embedded apk-in-apex, if any.
JW Wangc0d62772020-01-10 14:37:21 +08001148 if (!rollback.allPackagesEnabled()) {
Mohammad Samiul Islam3ffedc42020-01-06 13:53:16 +00001149 Slog.e(TAG, "Failed to enable rollback for all packages in session.");
JW Wangb18925b2020-02-11 16:20:06 +08001150 mRollbacks.remove(rollback);
Mohammad Samiul Islam3ffedc42020-01-06 13:53:16 +00001151 rollback.delete(mAppDataRollbackHelper);
JW Wang38a56562020-02-11 15:37:19 +08001152 return false;
Mohammad Samiul Islam3ffedc42020-01-06 13:53:16 +00001153 }
Oli Lan4af2f752019-09-27 10:39:32 +01001154
JW Wangb18925b2020-02-11 16:20:06 +08001155 // Note: There is a small window of time between when
1156 // the session has been committed by the package
1157 // manager and when we make the rollback available
1158 // here. Presumably the window is small enough that
1159 // nobody will want to roll back the newly installed
1160 // package before we make the rollback available.
1161 // TODO: We'll lose the rollback if the
1162 // device reboots between when the session is
1163 // committed and this point. Revisit this after
1164 // adding support for rollback of staged installs.
Oli Lan4af2f752019-09-27 10:39:32 +01001165 rollback.saveRollback();
Richard Uhler6f8a33b2019-02-26 10:40:36 +00001166
JW Wang38a56562020-02-11 15:37:19 +08001167 return true;
Richard Uhler6f8a33b2019-02-26 10:40:36 +00001168 }
1169
JW Wang53e89c92019-11-28 19:53:45 +08001170 @WorkerThread
Oli Lan8c0084d2019-09-11 13:38:43 +01001171 @GuardedBy("rollback.getLock")
Richard Uhler8d512ee2019-07-19 14:55:01 +01001172 private void makeRollbackAvailable(Rollback rollback) {
JW Wang12d0c3e2019-12-02 21:01:35 +08001173 if (LOCAL_LOGV) {
1174 Slog.v(TAG, "makeRollbackAvailable id=" + rollback.info.getRollbackId());
1175 }
Oli Lan7363a622019-09-13 10:06:12 +01001176 rollback.makeAvailable();
Richard Uhler6f8a33b2019-02-26 10:40:36 +00001177
1178 // TODO(zezeozue): Provide API to explicitly start observing instead
1179 // of doing this for all rollbacks. If we do this for all rollbacks,
1180 // should document in PackageInstaller.SessionParams#setEnableRollback
Oli Lan7363a622019-09-13 10:06:12 +01001181 // After enabling and committing any rollback, observe packages and
Richard Uhler6f8a33b2019-02-26 10:40:36 +00001182 // prepare to rollback if packages crashes too frequently.
Oli Lan3143ee32019-09-18 17:07:21 +01001183 mPackageHealthObserver.startObservingHealth(rollback.getPackageNames(),
Richard Uhler6f8a33b2019-02-26 10:40:36 +00001184 mRollbackLifetimeDurationInMillis);
1185 scheduleExpiration(mRollbackLifetimeDurationInMillis);
Richard Uhler035e9742019-01-09 13:11:07 +00001186 }
Richard Uhlerb9d54472019-01-22 12:50:08 +00001187
Richard Uhler0a79b322019-01-23 13:51:07 +00001188 /*
Richard Uhler8d512ee2019-07-19 14:55:01 +01001189 * Returns the rollback with the given rollbackId, if any.
Richard Uhler0a79b322019-01-23 13:51:07 +00001190 */
JW Wang53e89c92019-11-28 19:53:45 +08001191 @WorkerThread
Richard Uhler8d512ee2019-07-19 14:55:01 +01001192 private Rollback getRollbackForId(int rollbackId) {
Richard Uhler0a79b322019-01-23 13:51:07 +00001193 synchronized (mLock) {
Richard Uhler6f8a33b2019-02-26 10:40:36 +00001194 for (int i = 0; i < mRollbacks.size(); ++i) {
Richard Uhler8d512ee2019-07-19 14:55:01 +01001195 Rollback rollback = mRollbacks.get(i);
1196 if (rollback.info.getRollbackId() == rollbackId) {
1197 return rollback;
Richard Uhler0a79b322019-01-23 13:51:07 +00001198 }
1199 }
1200 }
Narayan Kamathc034fe92019-01-23 10:48:17 +00001201
1202 return null;
1203 }
1204
JW Wang53e89c92019-11-28 19:53:45 +08001205 @WorkerThread
Richard Uhlerb9d54472019-01-22 12:50:08 +00001206 @GuardedBy("mLock")
Richard Uhler47569702019-05-02 12:36:39 +01001207 private int allocateRollbackIdLocked() {
Richard Uhlerb9d54472019-01-22 12:50:08 +00001208 int n = 0;
1209 int rollbackId;
1210 do {
1211 rollbackId = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1;
1212 if (!mAllocatedRollbackIds.get(rollbackId, false)) {
1213 mAllocatedRollbackIds.put(rollbackId, true);
1214 return rollbackId;
1215 }
1216 } while (n++ < 32);
1217
Richard Uhler47569702019-05-02 12:36:39 +01001218 throw new IllegalStateException("Failed to allocate rollback ID");
Richard Uhlerb9d54472019-01-22 12:50:08 +00001219 }
Nikita Ioffe952aa7b2019-01-28 19:49:56 +00001220
shafik60046002019-03-12 17:54:10 +00001221 @Override
1222 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Oli Lan8753d822019-11-01 11:33:53 +00001223 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
1224
shafik60046002019-03-12 17:54:10 +00001225 IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
1226 synchronized (mLock) {
Richard Uhler8d512ee2019-07-19 14:55:01 +01001227 for (Rollback rollback : mRollbacks) {
Oli Lan4af2f752019-09-27 10:39:32 +01001228 rollback.dump(ipw);
shafik60046002019-03-12 17:54:10 +00001229 }
Gavin Corkeryefb3ff12019-12-02 18:15:24 +00001230 ipw.println();
1231 PackageWatchdog.getInstance(mContext).dump(ipw);
shafik60046002019-03-12 17:54:10 +00001232 }
1233 }
Richard Uhler1fc10c12019-03-18 11:38:46 +00001234
JW Wang53e89c92019-11-28 19:53:45 +08001235 @AnyThread
Richard Uhler1fc10c12019-03-18 11:38:46 +00001236 private void enforceManageRollbacks(@NonNull String message) {
1237 if ((PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
1238 Manifest.permission.MANAGE_ROLLBACKS))
1239 && (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
1240 Manifest.permission.TEST_MANAGE_ROLLBACKS))) {
1241 throw new SecurityException(message + " requires "
1242 + Manifest.permission.MANAGE_ROLLBACKS + " or "
1243 + Manifest.permission.TEST_MANAGE_ROLLBACKS);
1244 }
1245 }
Richard Uhler47569702019-05-02 12:36:39 +01001246
JW Wangb18925b2020-02-11 16:20:06 +08001247 /**
1248 * Creates and returns a Rollback according to the given SessionInfo
1249 * and adds it to {@link #mRollbacks}.
1250 */
JW Wang53e89c92019-11-28 19:53:45 +08001251 @WorkerThread
Oli Lan8c0084d2019-09-11 13:38:43 +01001252 @GuardedBy("mLock")
JW Wangab3064c2020-01-10 14:12:19 +08001253 private Rollback createNewRollbackLocked(PackageInstaller.SessionInfo parentSession) {
Richard Uhler47569702019-05-02 12:36:39 +01001254 int rollbackId = allocateRollbackIdLocked();
Gavin Corkery0987cb02019-10-07 10:46:55 +01001255 final int userId;
1256 if (parentSession.getUser() == UserHandle.ALL) {
1257 userId = UserHandle.USER_SYSTEM;
1258 } else {
1259 userId = parentSession.getUser().getIdentifier();
1260 }
1261 String installerPackageName = parentSession.getInstallerPackageName();
Richard Uhler8d512ee2019-07-19 14:55:01 +01001262 final Rollback rollback;
Richard Uhler47569702019-05-02 12:36:39 +01001263 int parentSessionId = parentSession.getSessionId();
1264
JW Wang12d0c3e2019-12-02 21:01:35 +08001265 if (LOCAL_LOGV) {
1266 Slog.v(TAG, "createNewRollback id=" + rollbackId
1267 + " user=" + userId + " installer=" + installerPackageName);
1268 }
1269
Richard Uhler47569702019-05-02 12:36:39 +01001270 int[] packageSessionIds;
1271 if (parentSession.isMultiPackage()) {
1272 packageSessionIds = parentSession.getChildSessionIds();
1273 } else {
1274 packageSessionIds = new int[]{parentSessionId};
1275 }
1276
JW Wangc3403cd2020-01-10 13:44:00 +08001277 if (parentSession.isStaged()) {
1278 rollback = mRollbackStore.createStagedRollback(rollbackId, parentSessionId, userId,
1279 installerPackageName, packageSessionIds);
1280 } else {
1281 rollback = mRollbackStore.createNonStagedRollback(rollbackId, userId,
1282 installerPackageName, packageSessionIds);
1283 }
1284
JW Wangb18925b2020-02-11 16:20:06 +08001285 mRollbacks.add(rollback);
JW Wangab3064c2020-01-10 14:12:19 +08001286 return rollback;
Richard Uhler47569702019-05-02 12:36:39 +01001287 }
1288
1289 /**
JW Wang1ac3d112020-02-07 15:52:36 +08001290 * Returns the Rollback associated with the given session if parent or child session id matches.
1291 * Returns null if not found.
1292 */
1293 @WorkerThread
1294 @GuardedBy("mLock")
1295 @Nullable
1296 private Rollback getRollbackForSessionLocked(int sessionId) {
1297 // We expect mRollbacks to be a very small list; linear search should be plenty fast.
1298 for (int i = 0; i < mRollbacks.size(); ++i) {
1299 Rollback rollback = mRollbacks.get(i);
1300 if (rollback.getStagedSessionId() == sessionId
1301 || rollback.containsSessionId(sessionId)) {
1302 return rollback;
1303 }
1304 }
1305 return null;
1306 }
Richard Uhlere95d0552018-12-27 15:03:41 +00001307}