• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 
17 package com.android.server.backup;
18 
19 import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND;
20 
21 import static com.android.server.backup.BackupManagerService.DEBUG;
22 import static com.android.server.backup.BackupManagerService.DEBUG_SCHEDULING;
23 import static com.android.server.backup.BackupManagerService.MORE_DEBUG;
24 import static com.android.server.backup.BackupManagerService.TAG;
25 import static com.android.server.backup.internal.BackupHandler.MSG_BACKUP_OPERATION_TIMEOUT;
26 import static com.android.server.backup.internal.BackupHandler.MSG_FULL_CONFIRMATION_TIMEOUT;
27 import static com.android.server.backup.internal.BackupHandler.MSG_OP_COMPLETE;
28 import static com.android.server.backup.internal.BackupHandler.MSG_REQUEST_BACKUP;
29 import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_OPERATION_TIMEOUT;
30 import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_SESSION_TIMEOUT;
31 import static com.android.server.backup.internal.BackupHandler.MSG_RETRY_CLEAR;
32 import static com.android.server.backup.internal.BackupHandler.MSG_RUN_ADB_BACKUP;
33 import static com.android.server.backup.internal.BackupHandler.MSG_RUN_ADB_RESTORE;
34 import static com.android.server.backup.internal.BackupHandler.MSG_RUN_BACKUP;
35 import static com.android.server.backup.internal.BackupHandler.MSG_RUN_CLEAR;
36 import static com.android.server.backup.internal.BackupHandler.MSG_RUN_RESTORE;
37 import static com.android.server.backup.internal.BackupHandler.MSG_SCHEDULE_BACKUP_PACKAGE;
38 
39 import android.annotation.Nullable;
40 import android.annotation.UserIdInt;
41 import android.app.ActivityManager;
42 import android.app.ActivityManagerInternal;
43 import android.app.AlarmManager;
44 import android.app.AppGlobals;
45 import android.app.IActivityManager;
46 import android.app.IBackupAgent;
47 import android.app.PendingIntent;
48 import android.app.backup.BackupAgent;
49 import android.app.backup.BackupManager;
50 import android.app.backup.BackupManager.OperationType;
51 import android.app.backup.BackupManagerMonitor;
52 import android.app.backup.FullBackup;
53 import android.app.backup.IBackupManager;
54 import android.app.backup.IBackupManagerMonitor;
55 import android.app.backup.IBackupObserver;
56 import android.app.backup.IFullBackupRestoreObserver;
57 import android.app.backup.IRestoreSession;
58 import android.app.backup.ISelectBackupTransportCallback;
59 import android.content.ActivityNotFoundException;
60 import android.content.BroadcastReceiver;
61 import android.content.ComponentName;
62 import android.content.ContentResolver;
63 import android.content.Context;
64 import android.content.Intent;
65 import android.content.IntentFilter;
66 import android.content.pm.ApplicationInfo;
67 import android.content.pm.IPackageManager;
68 import android.content.pm.PackageInfo;
69 import android.content.pm.PackageManager;
70 import android.content.pm.PackageManager.NameNotFoundException;
71 import android.content.pm.PackageManagerInternal;
72 import android.database.ContentObserver;
73 import android.net.Uri;
74 import android.os.Binder;
75 import android.os.Build;
76 import android.os.Bundle;
77 import android.os.Handler;
78 import android.os.HandlerThread;
79 import android.os.IBinder;
80 import android.os.Message;
81 import android.os.ParcelFileDescriptor;
82 import android.os.PowerManager;
83 import android.os.PowerManager.ServiceType;
84 import android.os.PowerSaveState;
85 import android.os.Process;
86 import android.os.RemoteException;
87 import android.os.SELinux;
88 import android.os.ServiceManager;
89 import android.os.SystemClock;
90 import android.os.UserHandle;
91 import android.os.WorkSource;
92 import android.os.storage.IStorageManager;
93 import android.os.storage.StorageManager;
94 import android.provider.Settings;
95 import android.text.TextUtils;
96 import android.util.ArraySet;
97 import android.util.AtomicFile;
98 import android.util.EventLog;
99 import android.util.FeatureFlagUtils;
100 import android.util.Pair;
101 import android.util.Slog;
102 import android.util.SparseArray;
103 
104 import com.android.internal.annotations.GuardedBy;
105 import com.android.internal.annotations.VisibleForTesting;
106 import com.android.internal.backup.IBackupTransport;
107 import com.android.internal.util.Preconditions;
108 import com.android.server.AppWidgetBackupBridge;
109 import com.android.server.EventLogTags;
110 import com.android.server.LocalServices;
111 import com.android.server.backup.fullbackup.FullBackupEntry;
112 import com.android.server.backup.fullbackup.PerformFullTransportBackupTask;
113 import com.android.server.backup.internal.BackupHandler;
114 import com.android.server.backup.internal.ClearDataObserver;
115 import com.android.server.backup.internal.OnTaskFinishedListener;
116 import com.android.server.backup.internal.Operation;
117 import com.android.server.backup.internal.PerformInitializeTask;
118 import com.android.server.backup.internal.RunInitializeReceiver;
119 import com.android.server.backup.internal.SetupObserver;
120 import com.android.server.backup.keyvalue.BackupRequest;
121 import com.android.server.backup.params.AdbBackupParams;
122 import com.android.server.backup.params.AdbParams;
123 import com.android.server.backup.params.AdbRestoreParams;
124 import com.android.server.backup.params.BackupParams;
125 import com.android.server.backup.params.ClearParams;
126 import com.android.server.backup.params.ClearRetryParams;
127 import com.android.server.backup.params.RestoreParams;
128 import com.android.server.backup.restore.ActiveRestoreSession;
129 import com.android.server.backup.restore.PerformUnifiedRestoreTask;
130 import com.android.server.backup.transport.TransportClient;
131 import com.android.server.backup.transport.TransportNotAvailableException;
132 import com.android.server.backup.transport.TransportNotRegisteredException;
133 import com.android.server.backup.utils.BackupEligibilityRules;
134 import com.android.server.backup.utils.BackupManagerMonitorUtils;
135 import com.android.server.backup.utils.BackupObserverUtils;
136 import com.android.server.backup.utils.SparseArrayUtils;
137 
138 import com.google.android.collect.Sets;
139 
140 import java.io.BufferedInputStream;
141 import java.io.ByteArrayOutputStream;
142 import java.io.DataInputStream;
143 import java.io.DataOutputStream;
144 import java.io.File;
145 import java.io.FileDescriptor;
146 import java.io.FileInputStream;
147 import java.io.FileNotFoundException;
148 import java.io.FileOutputStream;
149 import java.io.IOException;
150 import java.io.PrintWriter;
151 import java.io.RandomAccessFile;
152 import java.security.SecureRandom;
153 import java.text.SimpleDateFormat;
154 import java.util.ArrayDeque;
155 import java.util.ArrayList;
156 import java.util.Arrays;
157 import java.util.Collections;
158 import java.util.Date;
159 import java.util.HashMap;
160 import java.util.HashSet;
161 import java.util.LinkedHashSet;
162 import java.util.LinkedList;
163 import java.util.List;
164 import java.util.Objects;
165 import java.util.Queue;
166 import java.util.Random;
167 import java.util.Set;
168 import java.util.concurrent.CountDownLatch;
169 import java.util.concurrent.atomic.AtomicInteger;
170 
171 /** System service that performs backup/restore operations. */
172 public class UserBackupManagerService {
173     /**
174      * Wrapper over {@link PowerManager.WakeLock} to prevent double-free exceptions on release()
175      * after quit().
176      */
177     public static class BackupWakeLock {
178         private final PowerManager.WakeLock mPowerManagerWakeLock;
179         private boolean mHasQuit = false;
180         private int mUserId;
181 
BackupWakeLock(PowerManager.WakeLock powerManagerWakeLock, int userId)182         public BackupWakeLock(PowerManager.WakeLock powerManagerWakeLock, int userId) {
183             mPowerManagerWakeLock = powerManagerWakeLock;
184             mUserId = userId;
185         }
186 
187         /** Acquires the {@link PowerManager.WakeLock} if hasn't been quit. */
acquire()188         public synchronized void acquire() {
189             if (mHasQuit) {
190                 Slog.v(
191                         TAG,
192                         addUserIdToLogMessage(
193                                 mUserId,
194                                 "Ignore wakelock acquire after quit: "
195                                         + mPowerManagerWakeLock.getTag()));
196                 return;
197             }
198             mPowerManagerWakeLock.acquire();
199             Slog.v(
200                     TAG,
201                     addUserIdToLogMessage(
202                             mUserId, "Acquired wakelock:" + mPowerManagerWakeLock.getTag()));
203         }
204 
205         /** Releases the {@link PowerManager.WakeLock} if hasn't been quit. */
release()206         public synchronized void release() {
207             if (mHasQuit) {
208                 Slog.v(
209                         TAG,
210                         addUserIdToLogMessage(
211                                 mUserId,
212                                 "Ignore wakelock release after quit: "
213                                         + mPowerManagerWakeLock.getTag()));
214                 return;
215             }
216             mPowerManagerWakeLock.release();
217             Slog.v(
218                     TAG,
219                     addUserIdToLogMessage(
220                             mUserId, "Released wakelock:" + mPowerManagerWakeLock.getTag()));
221         }
222 
223         /**
224          * Returns true if the {@link PowerManager.WakeLock} has been acquired but not yet released.
225          */
isHeld()226         public synchronized boolean isHeld() {
227             return mPowerManagerWakeLock.isHeld();
228         }
229 
230         /** Release the {@link PowerManager.WakeLock} till it isn't held. */
quit()231         public synchronized void quit() {
232             while (mPowerManagerWakeLock.isHeld()) {
233                 Slog.v(
234                         TAG,
235                         addUserIdToLogMessage(
236                                 mUserId, "Releasing wakelock: " + mPowerManagerWakeLock.getTag()));
237                 mPowerManagerWakeLock.release();
238             }
239             mHasQuit = true;
240         }
241     }
242 
243     // Persistently track the need to do a full init.
244     private static final String INIT_SENTINEL_FILE_NAME = "_need_init_";
245 
246     // System-private key used for backing up an app's widget state.  Must
247     // begin with U+FFxx by convention (we reserve all keys starting
248     // with U+FF00 or higher for system use).
249     public static final String KEY_WIDGET_STATE = "\uffed\uffedwidget";
250 
251     // Name and current contents version of the full-backup manifest file
252     //
253     // Manifest version history:
254     //
255     // 1 : initial release
256     public static final String BACKUP_MANIFEST_FILENAME = "_manifest";
257     public static final int BACKUP_MANIFEST_VERSION = 1;
258 
259     // External archive format version history:
260     //
261     // 1 : initial release
262     // 2 : no format change per se; version bump to facilitate PBKDF2 version skew detection
263     // 3 : introduced "_meta" metadata file; no other format change per se
264     // 4 : added support for new device-encrypted storage locations
265     // 5 : added support for key-value packages
266     public static final int BACKUP_FILE_VERSION = 5;
267     public static final String BACKUP_FILE_HEADER_MAGIC = "ANDROID BACKUP\n";
268     public static final String BACKUP_METADATA_FILENAME = "_meta";
269     public static final int BACKUP_METADATA_VERSION = 1;
270     public static final int BACKUP_WIDGET_METADATA_TOKEN = 0x01FFED01;
271 
272     private static final int CURRENT_ANCESTRAL_RECORD_VERSION = 1;
273 
274     // Round-robin queue for scheduling full backup passes.
275     private static final int SCHEDULE_FILE_VERSION = 1;
276 
277     public static final String SETTINGS_PACKAGE = "com.android.providers.settings";
278     public static final String SHARED_BACKUP_AGENT_PACKAGE = "com.android.sharedstoragebackup";
279 
280     // Pseudoname that we use for the Package Manager metadata "package".
281     public static final String PACKAGE_MANAGER_SENTINEL = "@pm@";
282 
283     // Retry interval for clear/init when the transport is unavailable
284     private static final long TRANSPORT_RETRY_INTERVAL = 1 * AlarmManager.INTERVAL_HOUR;
285 
286     public static final String RUN_INITIALIZE_ACTION = "android.app.backup.intent.INIT";
287     private static final String BACKUP_FINISHED_ACTION = "android.intent.action.BACKUP_FINISHED";
288     private static final String BACKUP_FINISHED_PACKAGE_EXTRA = "packageName";
289 
290     // Bookkeeping of in-flight operations. The operation token is the index of the entry in the
291     // pending operations list.
292     public static final int OP_PENDING = 0;
293     private static final int OP_ACKNOWLEDGED = 1;
294     private static final int OP_TIMEOUT = -1;
295 
296     // Waiting for backup agent to respond during backup operation.
297     public static final int OP_TYPE_BACKUP_WAIT = 0;
298 
299     // Waiting for backup agent to respond during restore operation.
300     public static final int OP_TYPE_RESTORE_WAIT = 1;
301 
302     // An entire backup operation spanning multiple packages.
303     public static final int OP_TYPE_BACKUP = 2;
304 
305     // Time delay for initialization operations that can be delayed so as not to consume too much
306     // CPU on bring-up and increase time-to-UI.
307     private static final long INITIALIZATION_DELAY_MILLIS = 3000;
308 
309     // Timeout interval for deciding that a bind has taken too long.
310     private static final long BIND_TIMEOUT_INTERVAL = 10 * 1000;
311     // Timeout interval for deciding that a clear-data has taken too long.
312     private static final long CLEAR_DATA_TIMEOUT_INTERVAL = 30 * 1000;
313 
314     // User confirmation timeout for a full backup/restore operation.  It's this long in
315     // order to give them time to enter the backup password.
316     private static final long TIMEOUT_FULL_CONFIRMATION = 60 * 1000;
317 
318     // If an app is busy when we want to do a full-data backup, how long to defer the retry.
319     // This is fuzzed, so there are two parameters; backoff_min + Rand[0, backoff_fuzz)
320     private static final long BUSY_BACKOFF_MIN_MILLIS = 1000 * 60 * 60;  // one hour
321     private static final int BUSY_BACKOFF_FUZZ = 1000 * 60 * 60 * 2;  // two hours
322 
323     private static final String SERIAL_ID_FILE = "serial_id";
324 
325     private static final String SKIP_USER_FACING_PACKAGES = "backup_skip_user_facing_packages";
326     private static final String WALLPAPER_PACKAGE = "com.android.wallpaperbackup";
327 
328     private final @UserIdInt int mUserId;
329     private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
330     private final TransportManager mTransportManager;
331 
332     private final Context mContext;
333     private final PackageManager mPackageManager;
334     private final IPackageManager mPackageManagerBinder;
335     private final IActivityManager mActivityManager;
336     private final ActivityManagerInternal mActivityManagerInternal;
337     private PowerManager mPowerManager;
338     private final AlarmManager mAlarmManager;
339     private final IStorageManager mStorageManager;
340     private final BackupManagerConstants mConstants;
341     private final BackupWakeLock mWakelock;
342     private final BackupHandler mBackupHandler;
343     private final BackupEligibilityRules mScheduledBackupEligibility;
344 
345     private final IBackupManager mBackupManagerBinder;
346 
347     private boolean mEnabled;   // writes to this are synchronized on 'this'
348     private boolean mSetupComplete;
349     private boolean mAutoRestore;
350 
351     private final PendingIntent mRunInitIntent;
352 
353     private final ArraySet<String> mPendingInits = new ArraySet<>();  // transport names
354 
355     // map UIDs to the set of participating packages under that UID
356     private final SparseArray<HashSet<String>> mBackupParticipants = new SparseArray<>();
357 
358     // Backups that we haven't started yet.  Keys are package names.
359     private final HashMap<String, BackupRequest> mPendingBackups = new HashMap<>();
360 
361     // locking around the pending-backup management
362     private final Object mQueueLock = new Object();
363 
364     private final UserBackupPreferences mBackupPreferences;
365 
366     // The thread performing the sequence of queued backups binds to each app's agent
367     // in succession.  Bind notifications are asynchronously delivered through the
368     // Activity Manager; use this lock object to signal when a requested binding has
369     // completed.
370     private final Object mAgentConnectLock = new Object();
371     private IBackupAgent mConnectedAgent;
372     private volatile boolean mConnecting;
373 
374     private volatile boolean mBackupRunning;
375     private volatile long mLastBackupPass;
376 
377     // A similar synchronization mechanism around clearing apps' data for restore
378     private final Object mClearDataLock = new Object();
379     private volatile boolean mClearingData;
380 
381     // Used by ADB.
382     private final BackupPasswordManager mBackupPasswordManager;
383     private final SparseArray<AdbParams> mAdbBackupRestoreConfirmations = new SparseArray<>();
384     private final SecureRandom mRng = new SecureRandom();
385 
386     // Time when we post the transport registration operation
387     private final long mRegisterTransportsRequestedTime;
388 
389     @GuardedBy("mQueueLock")
390     private PerformFullTransportBackupTask mRunningFullBackupTask;
391 
392     @GuardedBy("mQueueLock")
393     private ArrayList<FullBackupEntry> mFullBackupQueue;
394 
395     @GuardedBy("mPendingRestores")
396     private boolean mIsRestoreInProgress;
397 
398     @GuardedBy("mPendingRestores")
399     private final Queue<PerformUnifiedRestoreTask> mPendingRestores = new ArrayDeque<>();
400 
401     private ActiveRestoreSession mActiveRestoreSession;
402 
403     /**
404      * mCurrentOperations contains the list of currently active operations.
405      *
406      * If type of operation is OP_TYPE_WAIT, it are waiting for an ack or timeout.
407      * An operation wraps a BackupRestoreTask within it.
408      * It's the responsibility of this task to remove the operation from this array.
409      *
410      * A BackupRestore task gets notified of ack/timeout for the operation via
411      * BackupRestoreTask#handleCancel, BackupRestoreTask#operationComplete and notifyAll called
412      * on the mCurrentOpLock.
413      * {@link UserBackupManagerService#waitUntilOperationComplete(int)} is
414      * used in various places to 'wait' for notifyAll and detect change of pending state of an
415      * operation. So typically, an operation will be removed from this array by:
416      * - BackupRestoreTask#handleCancel and
417      * - BackupRestoreTask#operationComplete OR waitUntilOperationComplete. Do not remove at both
418      * these places because waitUntilOperationComplete relies on the operation being present to
419      * determine its completion status.
420      *
421      * If type of operation is OP_BACKUP, it is a task running backups. It provides a handle to
422      * cancel backup tasks.
423      */
424     @GuardedBy("mCurrentOpLock")
425     private final SparseArray<Operation> mCurrentOperations = new SparseArray<>();
426     private final Object mCurrentOpLock = new Object();
427     private final Random mTokenGenerator = new Random();
428     private final AtomicInteger mNextToken = new AtomicInteger();
429 
430     // Where we keep our journal files and other bookkeeping.
431     private final File mBaseStateDir;
432     private final File mDataDir;
433     private final File mJournalDir;
434     @Nullable
435     private DataChangedJournal mJournal;
436     private final File mFullBackupScheduleFile;
437 
438     // Keep a log of all the apps we've ever backed up.
439     private ProcessedPackagesJournal mProcessedPackagesJournal;
440 
441     private File mTokenFile;
442     private Set<String> mAncestralPackages = null;
443     private long mAncestralToken = 0;
444     private long mCurrentToken = 0;
445     @Nullable private File mAncestralSerialNumberFile;
446     @OperationType private volatile long mAncestralOperationType;
447 
448     private final ContentObserver mSetupObserver;
449     private final BroadcastReceiver mRunInitReceiver;
450 
451     /**
452      * Creates an instance of {@link UserBackupManagerService} and initializes state for it. This
453      * includes setting up the directories where we keep our bookkeeping and transport management.
454      *
455      * @see #createAndInitializeService(int, Context, BackupManagerService, HandlerThread, File,
456      * File, TransportManager)
457      */
createAndInitializeService( @serIdInt int userId, Context context, BackupManagerService backupManagerService, Set<ComponentName> transportWhitelist)458     static UserBackupManagerService createAndInitializeService(
459             @UserIdInt int userId,
460             Context context,
461             BackupManagerService backupManagerService,
462             Set<ComponentName> transportWhitelist) {
463         String currentTransport =
464                 Settings.Secure.getStringForUser(
465                         context.getContentResolver(), Settings.Secure.BACKUP_TRANSPORT, userId);
466         if (TextUtils.isEmpty(currentTransport)) {
467             currentTransport = null;
468         }
469 
470         if (DEBUG) {
471             Slog.v(
472                     TAG,
473                     addUserIdToLogMessage(userId, "Starting with transport " + currentTransport));
474         }
475         TransportManager transportManager =
476                 new TransportManager(userId, context, transportWhitelist, currentTransport);
477 
478         File baseStateDir = UserBackupManagerFiles.getBaseStateDir(userId);
479         File dataDir = UserBackupManagerFiles.getDataDir(userId);
480 
481         HandlerThread userBackupThread =
482                 new HandlerThread("backup-" + userId, Process.THREAD_PRIORITY_BACKGROUND);
483         userBackupThread.start();
484         if (DEBUG) {
485             Slog.d(
486                     TAG,
487                     addUserIdToLogMessage(userId, "Started thread " + userBackupThread.getName()));
488         }
489 
490         return createAndInitializeService(
491                 userId,
492                 context,
493                 backupManagerService,
494                 userBackupThread,
495                 baseStateDir,
496                 dataDir,
497                 transportManager);
498     }
499 
500     /**
501      * Creates an instance of {@link UserBackupManagerService}.
502      *
503      * @param userId The user which this service is for.
504      * @param context The system server context.
505      * @param backupManagerService A reference to the proxy to {@link BackupManagerService}.
506      * @param userBackupThread The thread running backup/restore operations for the user.
507      * @param baseStateDir The directory we store the user's persistent bookkeeping data.
508      * @param dataDir The directory we store the user's temporary staging data.
509      * @param transportManager The {@link TransportManager} responsible for handling the user's
510      *     transports.
511      */
512     @VisibleForTesting
createAndInitializeService( @serIdInt int userId, Context context, BackupManagerService backupManagerService, HandlerThread userBackupThread, File baseStateDir, File dataDir, TransportManager transportManager)513     public static UserBackupManagerService createAndInitializeService(
514             @UserIdInt int userId,
515             Context context,
516             BackupManagerService backupManagerService,
517             HandlerThread userBackupThread,
518             File baseStateDir,
519             File dataDir,
520             TransportManager transportManager) {
521         return new UserBackupManagerService(
522                 userId,
523                 context,
524                 backupManagerService,
525                 userBackupThread,
526                 baseStateDir,
527                 dataDir,
528                 transportManager);
529     }
530 
531     /**
532      * Returns the value of {@link Settings.Secure#USER_SETUP_COMPLETE} for the specified user
533      * {@code userId} as a {@code boolean}.
534      */
getSetupCompleteSettingForUser(Context context, int userId)535     public static boolean getSetupCompleteSettingForUser(Context context, int userId) {
536         return Settings.Secure.getIntForUser(
537                 context.getContentResolver(),
538                 Settings.Secure.USER_SETUP_COMPLETE,
539                 0,
540                 userId)
541                 != 0;
542     }
543 
544     @VisibleForTesting
UserBackupManagerService(Context context, PackageManager packageManager)545     UserBackupManagerService(Context context, PackageManager packageManager) {
546         mContext = context;
547 
548         mUserId = 0;
549         mRegisterTransportsRequestedTime = 0;
550         mPackageManager = packageManager;
551 
552         mBaseStateDir = null;
553         mDataDir = null;
554         mJournalDir = null;
555         mFullBackupScheduleFile = null;
556         mSetupObserver = null;
557         mRunInitReceiver = null;
558         mRunInitIntent = null;
559         mAgentTimeoutParameters = null;
560         mTransportManager = null;
561         mActivityManagerInternal = null;
562         mAlarmManager = null;
563         mConstants = null;
564         mWakelock = null;
565         mBackupHandler = null;
566         mBackupPreferences = null;
567         mBackupPasswordManager = null;
568         mPackageManagerBinder = null;
569         mActivityManager = null;
570         mStorageManager = null;
571         mBackupManagerBinder = null;
572         mScheduledBackupEligibility = null;
573     }
574 
UserBackupManagerService( @serIdInt int userId, Context context, BackupManagerService parent, HandlerThread userBackupThread, File baseStateDir, File dataDir, TransportManager transportManager)575     private UserBackupManagerService(
576             @UserIdInt int userId,
577             Context context,
578             BackupManagerService parent,
579             HandlerThread userBackupThread,
580             File baseStateDir,
581             File dataDir,
582             TransportManager transportManager) {
583         mUserId = userId;
584         mContext = Objects.requireNonNull(context, "context cannot be null");
585         mPackageManager = context.getPackageManager();
586         mPackageManagerBinder = AppGlobals.getPackageManager();
587         mActivityManager = ActivityManager.getService();
588         mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
589         mScheduledBackupEligibility = getEligibilityRules(mPackageManager, userId,
590                 OperationType.BACKUP);
591 
592         mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
593         mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
594         mStorageManager = IStorageManager.Stub.asInterface(ServiceManager.getService("mount"));
595 
596         Objects.requireNonNull(parent, "parent cannot be null");
597         mBackupManagerBinder = BackupManagerService.asInterface(parent.asBinder());
598 
599         mAgentTimeoutParameters = new
600                 BackupAgentTimeoutParameters(Handler.getMain(), mContext.getContentResolver());
601         mAgentTimeoutParameters.start();
602 
603         Objects.requireNonNull(userBackupThread, "userBackupThread cannot be null");
604         mBackupHandler = new BackupHandler(this, userBackupThread);
605 
606         // Set up our bookkeeping
607         final ContentResolver resolver = context.getContentResolver();
608         mSetupComplete = getSetupCompleteSettingForUser(context, userId);
609         mAutoRestore = Settings.Secure.getIntForUser(resolver,
610                 Settings.Secure.BACKUP_AUTO_RESTORE, 1, userId) != 0;
611 
612         mSetupObserver = new SetupObserver(this, mBackupHandler);
613         resolver.registerContentObserver(
614                 Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE),
615                 /* notifyForDescendents */ false,
616                 mSetupObserver,
617                 mUserId);
618 
619         mBaseStateDir = Objects.requireNonNull(baseStateDir, "baseStateDir cannot be null");
620         // TODO (b/120424138): Remove once the system user is migrated to use the per-user CE
621         // directory. Per-user CE directories are managed by vold.
622         if (userId == UserHandle.USER_SYSTEM) {
623             mBaseStateDir.mkdirs();
624             if (!SELinux.restorecon(mBaseStateDir)) {
625                 Slog.w(
626                         TAG,
627                         addUserIdToLogMessage(
628                                 userId, "SELinux restorecon failed on " + mBaseStateDir));
629             }
630         }
631 
632         // TODO (b/120424138): The system user currently uses the cache which is managed by init.rc
633         // Initialization and restorecon is managed by vold for per-user CE directories.
634         mDataDir = Objects.requireNonNull(dataDir, "dataDir cannot be null");
635         mBackupPasswordManager = new BackupPasswordManager(mContext, mBaseStateDir, mRng);
636 
637         // Receiver for transport initialization.
638         mRunInitReceiver = new RunInitializeReceiver(this);
639         IntentFilter filter = new IntentFilter();
640         filter.addAction(RUN_INITIALIZE_ACTION);
641         context.registerReceiverAsUser(
642                 mRunInitReceiver,
643                 UserHandle.of(userId),
644                 filter,
645                 android.Manifest.permission.BACKUP,
646                 /* scheduler */ null);
647 
648         Intent initIntent = new Intent(RUN_INITIALIZE_ACTION);
649         initIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
650         mRunInitIntent =
651                 PendingIntent.getBroadcastAsUser(
652                         context,
653                         /* requestCode */ 0,
654                         initIntent,
655                         /* flags */ PendingIntent.FLAG_IMMUTABLE,
656                         UserHandle.of(userId));
657 
658         // Set up the backup-request journaling
659         mJournalDir = new File(mBaseStateDir, "pending");
660         mJournalDir.mkdirs();   // creates mBaseStateDir along the way
661         mJournal = null;        // will be created on first use
662 
663         mConstants = new BackupManagerConstants(mBackupHandler, mContext.getContentResolver());
664         // We are observing changes to the constants throughout the lifecycle of BMS. This is
665         // because we reference the constants in multiple areas of BMS, which otherwise would
666         // require frequent starting and stopping.
667         mConstants.start();
668 
669         // Build our mapping of uid to backup client services.  This implicitly
670         // schedules a backup pass on the Package Manager metadata the first
671         // time anything needs to be backed up.
672         synchronized (mBackupParticipants) {
673             addPackageParticipantsLocked(null);
674         }
675 
676         mTransportManager =
677                 Objects.requireNonNull(transportManager, "transportManager cannot be null");
678         mTransportManager.setOnTransportRegisteredListener(this::onTransportRegistered);
679         mRegisterTransportsRequestedTime = SystemClock.elapsedRealtime();
680         mBackupHandler.postDelayed(
681                 mTransportManager::registerTransports, INITIALIZATION_DELAY_MILLIS);
682 
683         // Now that we know about valid backup participants, parse any leftover journal files into
684         // the pending backup set
685         mBackupHandler.postDelayed(this::parseLeftoverJournals, INITIALIZATION_DELAY_MILLIS);
686 
687         mBackupPreferences = new UserBackupPreferences(mContext, mBaseStateDir);
688 
689         // Power management
690         mWakelock = new BackupWakeLock(
691                 mPowerManager.newWakeLock(
692                         PowerManager.PARTIAL_WAKE_LOCK,
693                         "*backup*-" + userId + "-" + userBackupThread.getThreadId()), userId);
694 
695         // Set up the various sorts of package tracking we do
696         mFullBackupScheduleFile = new File(mBaseStateDir, "fb-schedule");
697         initPackageTracking();
698     }
699 
700     @VisibleForTesting
initializeBackupEnableState()701     void initializeBackupEnableState() {
702         boolean isEnabled = readEnabledState();
703         // Don't persist value to disk since we just read it from there.
704         setBackupEnabled(isEnabled, /* persistToDisk */ false);
705     }
706 
707     /** Cleans up state when the user of this service is stopped. */
708     @VisibleForTesting
tearDownService()709     protected void tearDownService() {
710         mAgentTimeoutParameters.stop();
711         mConstants.stop();
712         mContext.getContentResolver().unregisterContentObserver(mSetupObserver);
713         mContext.unregisterReceiver(mRunInitReceiver);
714         mContext.unregisterReceiver(mPackageTrackingReceiver);
715         mBackupHandler.stop();
716     }
717 
getUserId()718     public @UserIdInt int getUserId() {
719         return mUserId;
720     }
721 
getConstants()722     public BackupManagerConstants getConstants() {
723         return mConstants;
724     }
725 
getAgentTimeoutParameters()726     public BackupAgentTimeoutParameters getAgentTimeoutParameters() {
727         return mAgentTimeoutParameters;
728     }
729 
getContext()730     public Context getContext() {
731         return mContext;
732     }
733 
getPackageManager()734     public PackageManager getPackageManager() {
735         return mPackageManager;
736     }
737 
getPackageManagerBinder()738     public IPackageManager getPackageManagerBinder() {
739         return mPackageManagerBinder;
740     }
741 
getActivityManager()742     public IActivityManager getActivityManager() {
743         return mActivityManager;
744     }
745 
getAlarmManager()746     public AlarmManager getAlarmManager() {
747         return mAlarmManager;
748     }
749 
750     @VisibleForTesting
setPowerManager(PowerManager powerManager)751     void setPowerManager(PowerManager powerManager) {
752         mPowerManager = powerManager;
753     }
754 
getTransportManager()755     public TransportManager getTransportManager() {
756         return mTransportManager;
757     }
758 
isEnabled()759     public boolean isEnabled() {
760         return mEnabled;
761     }
762 
setEnabled(boolean enabled)763     public void setEnabled(boolean enabled) {
764         mEnabled = enabled;
765     }
766 
isSetupComplete()767     public boolean isSetupComplete() {
768         return mSetupComplete;
769     }
770 
setSetupComplete(boolean setupComplete)771     public void setSetupComplete(boolean setupComplete) {
772         mSetupComplete = setupComplete;
773     }
774 
getWakelock()775     public BackupWakeLock getWakelock() {
776         return mWakelock;
777     }
778 
779     /**
780      * Sets the {@link WorkSource} of the {@link PowerManager.WakeLock} returned by {@link
781      * #getWakelock()}.
782      */
783     @VisibleForTesting
setWorkSource(@ullable WorkSource workSource)784     public void setWorkSource(@Nullable WorkSource workSource) {
785         // TODO: This is for testing, unfortunately WakeLock is final and WorkSource is not exposed
786         mWakelock.mPowerManagerWakeLock.setWorkSource(workSource);
787     }
788 
getBackupHandler()789     public Handler getBackupHandler() {
790         return mBackupHandler;
791     }
792 
getRunInitIntent()793     public PendingIntent getRunInitIntent() {
794         return mRunInitIntent;
795     }
796 
getPendingBackups()797     public HashMap<String, BackupRequest> getPendingBackups() {
798         return mPendingBackups;
799     }
800 
getQueueLock()801     public Object getQueueLock() {
802         return mQueueLock;
803     }
804 
isBackupRunning()805     public boolean isBackupRunning() {
806         return mBackupRunning;
807     }
808 
setBackupRunning(boolean backupRunning)809     public void setBackupRunning(boolean backupRunning) {
810         mBackupRunning = backupRunning;
811     }
812 
setLastBackupPass(long lastBackupPass)813     public void setLastBackupPass(long lastBackupPass) {
814         mLastBackupPass = lastBackupPass;
815     }
816 
getClearDataLock()817     public Object getClearDataLock() {
818         return mClearDataLock;
819     }
820 
setClearingData(boolean clearingData)821     public void setClearingData(boolean clearingData) {
822         mClearingData = clearingData;
823     }
824 
isRestoreInProgress()825     public boolean isRestoreInProgress() {
826         return mIsRestoreInProgress;
827     }
828 
setRestoreInProgress(boolean restoreInProgress)829     public void setRestoreInProgress(boolean restoreInProgress) {
830         mIsRestoreInProgress = restoreInProgress;
831     }
832 
getPendingRestores()833     public Queue<PerformUnifiedRestoreTask> getPendingRestores() {
834         return mPendingRestores;
835     }
836 
getActiveRestoreSession()837     public ActiveRestoreSession getActiveRestoreSession() {
838         return mActiveRestoreSession;
839     }
840 
getCurrentOperations()841     public SparseArray<Operation> getCurrentOperations() {
842         return mCurrentOperations;
843     }
844 
getCurrentOpLock()845     public Object getCurrentOpLock() {
846         return mCurrentOpLock;
847     }
848 
getAdbBackupRestoreConfirmations()849     public SparseArray<AdbParams> getAdbBackupRestoreConfirmations() {
850         return mAdbBackupRestoreConfirmations;
851     }
852 
getBaseStateDir()853     public File getBaseStateDir() {
854         return mBaseStateDir;
855     }
856 
getDataDir()857     public File getDataDir() {
858         return mDataDir;
859     }
860 
861     @VisibleForTesting
getPackageTrackingReceiver()862     BroadcastReceiver getPackageTrackingReceiver() {
863         return mPackageTrackingReceiver;
864     }
865 
866     @Nullable
getJournal()867     public DataChangedJournal getJournal() {
868         return mJournal;
869     }
870 
setJournal(@ullable DataChangedJournal journal)871     public void setJournal(@Nullable DataChangedJournal journal) {
872         mJournal = journal;
873     }
874 
getRng()875     public SecureRandom getRng() {
876         return mRng;
877     }
878 
setAncestralPackages(Set<String> ancestralPackages)879     public void setAncestralPackages(Set<String> ancestralPackages) {
880         mAncestralPackages = ancestralPackages;
881     }
882 
setAncestralToken(long ancestralToken)883     public void setAncestralToken(long ancestralToken) {
884         mAncestralToken = ancestralToken;
885     }
886 
setAncestralOperationType(@perationType int operationType)887     public void setAncestralOperationType(@OperationType int operationType) {
888         mAncestralOperationType = operationType;
889     }
890 
getCurrentToken()891     public long getCurrentToken() {
892         return mCurrentToken;
893     }
894 
setCurrentToken(long currentToken)895     public void setCurrentToken(long currentToken) {
896         mCurrentToken = currentToken;
897     }
898 
getPendingInits()899     public ArraySet<String> getPendingInits() {
900         return mPendingInits;
901     }
902 
903     /** Clear all pending transport initializations. */
clearPendingInits()904     public void clearPendingInits() {
905         mPendingInits.clear();
906     }
907 
setRunningFullBackupTask( PerformFullTransportBackupTask runningFullBackupTask)908     public void setRunningFullBackupTask(
909             PerformFullTransportBackupTask runningFullBackupTask) {
910         mRunningFullBackupTask = runningFullBackupTask;
911     }
912 
913     /**
914      *  Utility: build a new random integer token. The low bits are the ordinal of the operation for
915      *  near-time uniqueness, and the upper bits are random for app-side unpredictability.
916      */
generateRandomIntegerToken()917     public int generateRandomIntegerToken() {
918         int token = mTokenGenerator.nextInt();
919         if (token < 0) token = -token;
920         token &= ~0xFF;
921         token |= (mNextToken.incrementAndGet() & 0xFF);
922         return token;
923     }
924 
925     /**
926      * Construct a backup agent instance for the metadata pseudopackage. This is a process-local
927      * non-lifecycle agent instance, so we manually set up the context topology for it.
928      */
makeMetadataAgent()929     public BackupAgent makeMetadataAgent() {
930         return makeMetadataAgentWithEligibilityRules(mScheduledBackupEligibility);
931     }
932 
makeMetadataAgentWithEligibilityRules( BackupEligibilityRules backupEligibilityRules)933     public BackupAgent makeMetadataAgentWithEligibilityRules(
934             BackupEligibilityRules backupEligibilityRules) {
935         PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(mPackageManager, mUserId,
936                 backupEligibilityRules);
937         pmAgent.attach(mContext);
938         pmAgent.onCreate(UserHandle.of(mUserId));
939         return pmAgent;
940     }
941 
942     /**
943      * Same as {@link #makeMetadataAgent()} but with explicit package-set configuration.
944      */
makeMetadataAgent(List<PackageInfo> packages)945     public PackageManagerBackupAgent makeMetadataAgent(List<PackageInfo> packages) {
946         PackageManagerBackupAgent pmAgent =
947                 new PackageManagerBackupAgent(mPackageManager, packages, mUserId);
948         pmAgent.attach(mContext);
949         pmAgent.onCreate(UserHandle.of(mUserId));
950         return pmAgent;
951     }
952 
initPackageTracking()953     private void initPackageTracking() {
954         if (MORE_DEBUG) Slog.v(TAG, addUserIdToLogMessage(mUserId, "` tracking"));
955 
956         // Remember our ancestral dataset
957         mTokenFile = new File(mBaseStateDir, "ancestral");
958         try (DataInputStream tokenStream = new DataInputStream(new BufferedInputStream(
959                 new FileInputStream(mTokenFile)))) {
960             int version = tokenStream.readInt();
961             if (version == CURRENT_ANCESTRAL_RECORD_VERSION) {
962                 mAncestralToken = tokenStream.readLong();
963                 mCurrentToken = tokenStream.readLong();
964 
965                 int numPackages = tokenStream.readInt();
966                 if (numPackages >= 0) {
967                     mAncestralPackages = new HashSet<>();
968                     for (int i = 0; i < numPackages; i++) {
969                         String pkgName = tokenStream.readUTF();
970                         mAncestralPackages.add(pkgName);
971                     }
972                 }
973             }
974         } catch (FileNotFoundException fnf) {
975             // Probably innocuous
976             Slog.v(TAG, addUserIdToLogMessage(mUserId, "No ancestral data"));
977         } catch (IOException e) {
978             Slog.w(TAG, addUserIdToLogMessage(mUserId, "Unable to read token file"), e);
979         }
980 
981         mProcessedPackagesJournal = new ProcessedPackagesJournal(mBaseStateDir);
982         mProcessedPackagesJournal.init();
983 
984         synchronized (mQueueLock) {
985             // Resume the full-data backup queue
986             mFullBackupQueue = readFullBackupSchedule();
987         }
988 
989         // Register for broadcasts about package changes.
990         IntentFilter filter = new IntentFilter();
991         filter.addAction(Intent.ACTION_PACKAGE_ADDED);
992         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
993         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
994         filter.addDataScheme("package");
995         mContext.registerReceiverAsUser(
996                 mPackageTrackingReceiver,
997                 UserHandle.of(mUserId),
998                 filter,
999                 /* broadcastPermission */ null,
1000                 /* scheduler */ null);
1001 
1002         // Register for events related to sdcard installation.
1003         IntentFilter sdFilter = new IntentFilter();
1004         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
1005         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
1006         mContext.registerReceiverAsUser(
1007                 mPackageTrackingReceiver,
1008                 UserHandle.of(mUserId),
1009                 sdFilter,
1010                 /* broadcastPermission */ null,
1011                 /* scheduler */ null);
1012     }
1013 
readFullBackupSchedule()1014     private ArrayList<FullBackupEntry> readFullBackupSchedule() {
1015         boolean changed = false;
1016         ArrayList<FullBackupEntry> schedule = null;
1017         List<PackageInfo> apps =
1018                 PackageManagerBackupAgent.getStorableApplications(mPackageManager, mUserId,
1019                         mScheduledBackupEligibility);
1020 
1021         if (mFullBackupScheduleFile.exists()) {
1022             try (FileInputStream fstream = new FileInputStream(mFullBackupScheduleFile);
1023                  BufferedInputStream bufStream = new BufferedInputStream(fstream);
1024                  DataInputStream in = new DataInputStream(bufStream)) {
1025                 int version = in.readInt();
1026                 if (version != SCHEDULE_FILE_VERSION) {
1027                     Slog.e(
1028                             TAG,
1029                             addUserIdToLogMessage(
1030                                     mUserId, "Unknown backup schedule version " + version));
1031                     return null;
1032                 }
1033 
1034                 final int numPackages = in.readInt();
1035                 schedule = new ArrayList<>(numPackages);
1036 
1037                 // HashSet instead of ArraySet specifically because we want the eventual
1038                 // lookups against O(hundreds) of entries to be as fast as possible, and
1039                 // we discard the set immediately after the scan so the extra memory
1040                 // overhead is transient.
1041                 HashSet<String> foundApps = new HashSet<>(numPackages);
1042 
1043                 for (int i = 0; i < numPackages; i++) {
1044                     String pkgName = in.readUTF();
1045                     long lastBackup = in.readLong();
1046                     foundApps.add(pkgName); // all apps that we've addressed already
1047                     try {
1048                         PackageInfo pkg = mPackageManager.getPackageInfoAsUser(pkgName, 0, mUserId);
1049                         if (mScheduledBackupEligibility.appGetsFullBackup(pkg)
1050                                 && mScheduledBackupEligibility.appIsEligibleForBackup(
1051                                         pkg.applicationInfo)) {
1052                             schedule.add(new FullBackupEntry(pkgName, lastBackup));
1053                         } else {
1054                             if (DEBUG) {
1055                                 Slog.i(TAG, addUserIdToLogMessage(mUserId, "Package " + pkgName
1056                                         + " no longer eligible for full backup"));
1057                             }
1058                         }
1059                     } catch (NameNotFoundException e) {
1060                         if (DEBUG) {
1061                             Slog.i(TAG, addUserIdToLogMessage(mUserId, "Package " + pkgName
1062                                     + " not installed; dropping from full backup"));
1063                         }
1064                     }
1065                 }
1066 
1067                 // New apps can arrive "out of band" via OTA and similar, so we also need to
1068                 // scan to make sure that we're tracking all full-backup candidates properly
1069                 for (PackageInfo app : apps) {
1070                     if (mScheduledBackupEligibility.appGetsFullBackup(app)
1071                             && mScheduledBackupEligibility.appIsEligibleForBackup(
1072                                     app.applicationInfo)) {
1073                         if (!foundApps.contains(app.packageName)) {
1074                             if (MORE_DEBUG) {
1075                                 Slog.i(
1076                                         TAG,
1077                                         addUserIdToLogMessage(
1078                                                 mUserId,
1079                                                 "New full backup app "
1080                                                         + app.packageName
1081                                                         + " found"));
1082                             }
1083                             schedule.add(new FullBackupEntry(app.packageName, 0));
1084                             changed = true;
1085                         }
1086                     }
1087                 }
1088 
1089                 Collections.sort(schedule);
1090             } catch (Exception e) {
1091                 Slog.e(TAG, addUserIdToLogMessage(mUserId, "Unable to read backup schedule"), e);
1092                 mFullBackupScheduleFile.delete();
1093                 schedule = null;
1094             }
1095         }
1096 
1097         if (schedule == null) {
1098             // no prior queue record, or unable to read it.  Set up the queue
1099             // from scratch.
1100             changed = true;
1101             schedule = new ArrayList<>(apps.size());
1102             for (PackageInfo info : apps) {
1103                 if (mScheduledBackupEligibility.appGetsFullBackup(info)
1104                         && mScheduledBackupEligibility.appIsEligibleForBackup(
1105                                 info.applicationInfo)) {
1106                     schedule.add(new FullBackupEntry(info.packageName, 0));
1107                 }
1108             }
1109         }
1110 
1111         if (changed) {
1112             writeFullBackupScheduleAsync();
1113         }
1114         return schedule;
1115     }
1116 
1117     private Runnable mFullBackupScheduleWriter = new Runnable() {
1118         @Override
1119         public void run() {
1120             synchronized (mQueueLock) {
1121                 try {
1122                     ByteArrayOutputStream bufStream = new ByteArrayOutputStream(4096);
1123                     DataOutputStream bufOut = new DataOutputStream(bufStream);
1124                     bufOut.writeInt(SCHEDULE_FILE_VERSION);
1125 
1126                     // version 1:
1127                     //
1128                     // [int] # of packages in the queue = N
1129                     // N * {
1130                     //     [utf8] package name
1131                     //     [long] last backup time for this package
1132                     //     }
1133                     int numPackages = mFullBackupQueue.size();
1134                     bufOut.writeInt(numPackages);
1135 
1136                     for (int i = 0; i < numPackages; i++) {
1137                         FullBackupEntry entry = mFullBackupQueue.get(i);
1138                         bufOut.writeUTF(entry.packageName);
1139                         bufOut.writeLong(entry.lastBackup);
1140                     }
1141                     bufOut.flush();
1142 
1143                     AtomicFile af = new AtomicFile(mFullBackupScheduleFile);
1144                     FileOutputStream out = af.startWrite();
1145                     out.write(bufStream.toByteArray());
1146                     af.finishWrite(out);
1147                 } catch (Exception e) {
1148                     Slog.e(
1149                             TAG,
1150                             addUserIdToLogMessage(
1151                                     mUserId, "Unable to write backup schedule!"),
1152                             e);
1153                 }
1154             }
1155         }
1156     };
1157 
writeFullBackupScheduleAsync()1158     private void writeFullBackupScheduleAsync() {
1159         mBackupHandler.removeCallbacks(mFullBackupScheduleWriter);
1160         mBackupHandler.post(mFullBackupScheduleWriter);
1161     }
1162 
parseLeftoverJournals()1163     private void parseLeftoverJournals() {
1164         ArrayList<DataChangedJournal> journals = DataChangedJournal.listJournals(mJournalDir);
1165         journals.removeAll(Collections.singletonList(mJournal));
1166         if (!journals.isEmpty()) {
1167             Slog.i(TAG, addUserIdToLogMessage(mUserId,
1168                     "Found " + journals.size() + " stale backup journal(s), scheduling."));
1169         }
1170         Set<String> packageNames = new LinkedHashSet<>();
1171         for (DataChangedJournal journal : journals) {
1172             try {
1173                 journal.forEach(packageName -> {
1174                     if (packageNames.add(packageName)) {
1175                         dataChangedImpl(packageName);
1176                     }
1177                 });
1178             } catch (IOException e) {
1179                 Slog.e(TAG, addUserIdToLogMessage(mUserId, "Can't read " + journal), e);
1180             }
1181         }
1182         if (!packageNames.isEmpty()) {
1183             String msg = "Stale backup journals: Scheduled " + packageNames.size()
1184                     + " package(s) total";
1185             if (MORE_DEBUG) {
1186                 msg += ": " + packageNames;
1187             }
1188             Slog.i(TAG, addUserIdToLogMessage(mUserId, msg));
1189         }
1190     }
1191 
getExcludedRestoreKeys(String packageName)1192     public Set<String> getExcludedRestoreKeys(String packageName) {
1193         return mBackupPreferences.getExcludedRestoreKeysForPackage(packageName);
1194     }
1195 
1196     /** Used for generating random salts or passwords. */
randomBytes(int bits)1197     public byte[] randomBytes(int bits) {
1198         byte[] array = new byte[bits / 8];
1199         mRng.nextBytes(array);
1200         return array;
1201     }
1202 
1203     /** For adb backup/restore. */
setBackupPassword(String currentPw, String newPw)1204     public boolean setBackupPassword(String currentPw, String newPw) {
1205         return mBackupPasswordManager.setBackupPassword(currentPw, newPw);
1206     }
1207 
1208     /** For adb backup/restore. */
hasBackupPassword()1209     public boolean hasBackupPassword() {
1210         return mBackupPasswordManager.hasBackupPassword();
1211     }
1212 
1213     /** For adb backup/restore. */
backupPasswordMatches(String currentPw)1214     public boolean backupPasswordMatches(String currentPw) {
1215         return mBackupPasswordManager.backupPasswordMatches(currentPw);
1216     }
1217 
1218     /**
1219      * Maintain persistent state around whether need to do an initialize operation. This will lock
1220      * on {@link #getQueueLock()}.
1221      */
recordInitPending( boolean isPending, String transportName, String transportDirName)1222     public void recordInitPending(
1223             boolean isPending, String transportName, String transportDirName) {
1224         synchronized (mQueueLock) {
1225             if (MORE_DEBUG) {
1226                 Slog.i(
1227                         TAG,
1228                         addUserIdToLogMessage(
1229                                 mUserId,
1230                                 "recordInitPending("
1231                                         + isPending
1232                                         + ") on transport "
1233                                         + transportName));
1234             }
1235 
1236             File stateDir = new File(mBaseStateDir, transportDirName);
1237             File initPendingFile = new File(stateDir, INIT_SENTINEL_FILE_NAME);
1238 
1239             if (isPending) {
1240                 // We need an init before we can proceed with sending backup data.
1241                 // Record that with an entry in our set of pending inits, as well as
1242                 // journaling it via creation of a sentinel file.
1243                 mPendingInits.add(transportName);
1244                 try {
1245                     (new FileOutputStream(initPendingFile)).close();
1246                 } catch (IOException ioe) {
1247                     // Something is badly wrong with our permissions; just try to move on
1248                 }
1249             } else {
1250                 // No more initialization needed; wipe the journal and reset our state.
1251                 initPendingFile.delete();
1252                 mPendingInits.remove(transportName);
1253             }
1254         }
1255     }
1256 
1257     /**
1258      * Reset all of our bookkeeping because the backend data has been wiped (for example due to idle
1259      * expiry), so we must re-upload all saved settings.
1260      */
resetBackupState(File stateFileDir)1261     public void resetBackupState(File stateFileDir) {
1262         synchronized (mQueueLock) {
1263             mProcessedPackagesJournal.reset();
1264 
1265             mCurrentToken = 0;
1266             writeRestoreTokens();
1267 
1268             // Remove all the state files
1269             for (File sf : stateFileDir.listFiles()) {
1270                 // ... but don't touch the needs-init sentinel
1271                 if (!sf.getName().equals(INIT_SENTINEL_FILE_NAME)) {
1272                     sf.delete();
1273                 }
1274             }
1275         }
1276 
1277         // Enqueue a new backup of every participant
1278         synchronized (mBackupParticipants) {
1279             final int numParticipants = mBackupParticipants.size();
1280             for (int i = 0; i < numParticipants; i++) {
1281                 HashSet<String> participants = mBackupParticipants.valueAt(i);
1282                 if (participants != null) {
1283                     for (String packageName : participants) {
1284                         dataChangedImpl(packageName);
1285                     }
1286                 }
1287             }
1288         }
1289     }
1290 
onTransportRegistered(String transportName, String transportDirName)1291     private void onTransportRegistered(String transportName, String transportDirName) {
1292         if (DEBUG) {
1293             long timeMs = SystemClock.elapsedRealtime() - mRegisterTransportsRequestedTime;
1294             Slog.d(
1295                     TAG,
1296                     addUserIdToLogMessage(
1297                             mUserId,
1298                             "Transport "
1299                                     + transportName
1300                                     + " registered "
1301                                     + timeMs
1302                                     + "ms after first request (delay = "
1303                                     + INITIALIZATION_DELAY_MILLIS
1304                                     + "ms)"));
1305         }
1306 
1307         File stateDir = new File(mBaseStateDir, transportDirName);
1308         stateDir.mkdirs();
1309 
1310         File initSentinel = new File(stateDir, INIT_SENTINEL_FILE_NAME);
1311         if (initSentinel.exists()) {
1312             synchronized (mQueueLock) {
1313                 mPendingInits.add(transportName);
1314 
1315                 // TODO: pick a better starting time than now + 1 minute
1316                 long delay = 1000 * 60; // one minute, in milliseconds
1317                 mAlarmManager.set(AlarmManager.RTC_WAKEUP,
1318                         System.currentTimeMillis() + delay, mRunInitIntent);
1319             }
1320         }
1321     }
1322 
1323     /**
1324      * A {@link BroadcastReceiver} tracking changes to packages and sd cards in order to update our
1325      * internal bookkeeping.
1326      */
1327     private BroadcastReceiver mPackageTrackingReceiver = new BroadcastReceiver() {
1328         public void onReceive(Context context, Intent intent) {
1329             if (MORE_DEBUG) {
1330                 Slog.d(TAG, addUserIdToLogMessage(mUserId, "Received broadcast " + intent));
1331             }
1332 
1333             String action = intent.getAction();
1334             boolean replacing = false;
1335             boolean added = false;
1336             boolean changed = false;
1337             Bundle extras = intent.getExtras();
1338             String[] packageList = null;
1339 
1340             if (Intent.ACTION_PACKAGE_ADDED.equals(action)
1341                     || Intent.ACTION_PACKAGE_REMOVED.equals(action)
1342                     || Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
1343                 Uri uri = intent.getData();
1344                 if (uri == null) {
1345                     return;
1346                 }
1347 
1348                 String packageName = uri.getSchemeSpecificPart();
1349                 if (packageName != null) {
1350                     packageList = new String[] {packageName};
1351                 }
1352 
1353                 changed = Intent.ACTION_PACKAGE_CHANGED.equals(action);
1354                 if (changed) {
1355                     // Look at new transport states for package changed events.
1356                     String[] components =
1357                             intent.getStringArrayExtra(
1358                                     Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
1359 
1360                     if (MORE_DEBUG) {
1361                         Slog.i(
1362                                 TAG,
1363                                 addUserIdToLogMessage(
1364                                         mUserId, "Package " + packageName + " changed"));
1365                         for (int i = 0; i < components.length; i++) {
1366                             Slog.i(
1367                                     TAG,
1368                                     addUserIdToLogMessage(
1369                                             mUserId, "   * " + components[i]));
1370                         }
1371                     }
1372 
1373                     mBackupHandler.post(
1374                             () ->
1375                                     mTransportManager.onPackageChanged(
1376                                             packageName, components));
1377                     return;
1378                 }
1379 
1380                 added = Intent.ACTION_PACKAGE_ADDED.equals(action);
1381                 replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false);
1382             } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
1383                 added = true;
1384                 packageList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
1385             } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
1386                 added = false;
1387                 packageList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
1388             }
1389 
1390             if (packageList == null || packageList.length == 0) {
1391                 return;
1392             }
1393 
1394             int uid = extras.getInt(Intent.EXTRA_UID);
1395             if (added) {
1396                 synchronized (mBackupParticipants) {
1397                     if (replacing) {
1398                         // Remove the entry under the old uid and fall through to re-add. If
1399                         // an app
1400                         // just opted into key/value backup, add it as a known participant.
1401                         removePackageParticipantsLocked(packageList, uid);
1402                     }
1403                     addPackageParticipantsLocked(packageList);
1404                 }
1405 
1406                 long now = System.currentTimeMillis();
1407                 for (String packageName : packageList) {
1408                     try {
1409                         PackageInfo app =
1410                                 mPackageManager.getPackageInfoAsUser(
1411                                         packageName, /* flags */ 0, mUserId);
1412                         if (mScheduledBackupEligibility.appGetsFullBackup(app)
1413                                 && mScheduledBackupEligibility.appIsEligibleForBackup(
1414                                         app.applicationInfo)) {
1415                             enqueueFullBackup(packageName, now);
1416                             scheduleNextFullBackupJob(0);
1417                         } else {
1418                             // The app might have just transitioned out of full-data into
1419                             // doing
1420                             // key/value backups, or might have just disabled backups
1421                             // entirely. Make
1422                             // sure it is no longer in the full-data queue.
1423                             synchronized (mQueueLock) {
1424                                 dequeueFullBackupLocked(packageName);
1425                             }
1426                             writeFullBackupScheduleAsync();
1427                         }
1428 
1429                         mBackupHandler.post(
1430                                 () -> mTransportManager.onPackageAdded(packageName));
1431                     } catch (NameNotFoundException e) {
1432                         if (DEBUG) {
1433                             Slog.w(
1434                                     TAG,
1435                                     addUserIdToLogMessage(
1436                                             mUserId,
1437                                             "Can't resolve new app " + packageName));
1438                         }
1439                     }
1440                 }
1441 
1442                 // Whenever a package is added or updated we need to update the package
1443                 // metadata
1444                 // bookkeeping.
1445                 dataChangedImpl(PACKAGE_MANAGER_SENTINEL);
1446             } else {
1447                 if (!replacing) {
1448                     // Outright removal. In the full-data case, the app will be dropped from
1449                     // the
1450                     // queue when its (now obsolete) name comes up again for backup.
1451                     synchronized (mBackupParticipants) {
1452                         removePackageParticipantsLocked(packageList, uid);
1453                     }
1454                 }
1455 
1456                 for (String packageName : packageList) {
1457                     mBackupHandler.post(
1458                             () -> mTransportManager.onPackageRemoved(packageName));
1459                 }
1460             }
1461         }
1462     };
1463 
1464     // Add the backup agents in the given packages to our set of known backup participants.
1465     // If 'packageNames' is null, adds all backup agents in the whole system.
addPackageParticipantsLocked(String[] packageNames)1466     private void addPackageParticipantsLocked(String[] packageNames) {
1467         // Look for apps that define the android:backupAgent attribute
1468         List<PackageInfo> targetApps = allAgentPackages();
1469         if (packageNames != null) {
1470             if (MORE_DEBUG) {
1471                 Slog.v(
1472                         TAG,
1473                         addUserIdToLogMessage(
1474                                 mUserId, "addPackageParticipantsLocked: #" + packageNames.length));
1475             }
1476             for (String packageName : packageNames) {
1477                 addPackageParticipantsLockedInner(packageName, targetApps);
1478             }
1479         } else {
1480             if (MORE_DEBUG) {
1481                 Slog.v(TAG, addUserIdToLogMessage(mUserId, "addPackageParticipantsLocked: all"));
1482             }
1483             addPackageParticipantsLockedInner(null, targetApps);
1484         }
1485     }
1486 
addPackageParticipantsLockedInner(String packageName, List<PackageInfo> targetPkgs)1487     private void addPackageParticipantsLockedInner(String packageName,
1488             List<PackageInfo> targetPkgs) {
1489         if (MORE_DEBUG) {
1490             Slog.v(
1491                     TAG,
1492                     addUserIdToLogMessage(
1493                             mUserId, "Examining " + packageName + " for backup agent"));
1494         }
1495 
1496         for (PackageInfo pkg : targetPkgs) {
1497             if (packageName == null || pkg.packageName.equals(packageName)) {
1498                 int uid = pkg.applicationInfo.uid;
1499                 HashSet<String> set = mBackupParticipants.get(uid);
1500                 if (set == null) {
1501                     set = new HashSet<>();
1502                     mBackupParticipants.put(uid, set);
1503                 }
1504                 set.add(pkg.packageName);
1505                 if (MORE_DEBUG) Slog.v(TAG, addUserIdToLogMessage(mUserId, "Agent found; added"));
1506 
1507                 // Schedule a backup for it on general principles
1508                 if (MORE_DEBUG) {
1509                     Slog.i(
1510                             TAG,
1511                             addUserIdToLogMessage(
1512                                     mUserId, "Scheduling backup for new app " + pkg.packageName));
1513                 }
1514                 Message msg = mBackupHandler
1515                         .obtainMessage(MSG_SCHEDULE_BACKUP_PACKAGE, pkg.packageName);
1516                 mBackupHandler.sendMessage(msg);
1517             }
1518         }
1519     }
1520 
1521     // Remove the given packages' entries from our known active set.
removePackageParticipantsLocked(String[] packageNames, int oldUid)1522     private void removePackageParticipantsLocked(String[] packageNames, int oldUid) {
1523         if (packageNames == null) {
1524             Slog.w(TAG, addUserIdToLogMessage(mUserId, "removePackageParticipants with null list"));
1525             return;
1526         }
1527 
1528         if (MORE_DEBUG) {
1529             Slog.v(
1530                     TAG,
1531                     addUserIdToLogMessage(
1532                             mUserId,
1533                             "removePackageParticipantsLocked: uid="
1534                                     + oldUid
1535                                     + " #"
1536                                     + packageNames.length));
1537         }
1538         for (String pkg : packageNames) {
1539             // Known previous UID, so we know which package set to check
1540             HashSet<String> set = mBackupParticipants.get(oldUid);
1541             if (set != null && set.contains(pkg)) {
1542                 removePackageFromSetLocked(set, pkg);
1543                 if (set.isEmpty()) {
1544                     if (MORE_DEBUG) {
1545                         Slog.v(
1546                                 TAG,
1547                                 addUserIdToLogMessage(
1548                                         mUserId, "  last one of this uid; purging set"));
1549                     }
1550                     mBackupParticipants.remove(oldUid);
1551                 }
1552             }
1553         }
1554     }
1555 
removePackageFromSetLocked(final HashSet<String> set, final String packageName)1556     private void removePackageFromSetLocked(final HashSet<String> set,
1557             final String packageName) {
1558         if (set.contains(packageName)) {
1559             // Found it.  Remove this one package from the bookkeeping, and
1560             // if it's the last participating app under this uid we drop the
1561             // (now-empty) set as well.
1562             // Note that we deliberately leave it 'known' in the "ever backed up"
1563             // bookkeeping so that its current-dataset data will be retrieved
1564             // if the app is subsequently reinstalled
1565             if (MORE_DEBUG) {
1566                 Slog.v(
1567                         TAG,
1568                         addUserIdToLogMessage(mUserId, "  removing participant " + packageName));
1569             }
1570             set.remove(packageName);
1571             mPendingBackups.remove(packageName);
1572         }
1573     }
1574 
1575     // Returns the set of all applications that define an android:backupAgent attribute
allAgentPackages()1576     private List<PackageInfo> allAgentPackages() {
1577         // !!! TODO: cache this and regenerate only when necessary
1578         int flags = PackageManager.GET_SIGNING_CERTIFICATES;
1579         List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(flags, mUserId);
1580         int numPackages = packages.size();
1581         for (int a = numPackages - 1; a >= 0; a--) {
1582             PackageInfo pkg = packages.get(a);
1583             try {
1584                 ApplicationInfo app = pkg.applicationInfo;
1585                 if (((app.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0)
1586                         || app.backupAgentName == null
1587                         || (app.flags & ApplicationInfo.FLAG_FULL_BACKUP_ONLY) != 0) {
1588                     packages.remove(a);
1589                 } else {
1590                     // we will need the shared library path, so look that up and store it here.
1591                     // This is used implicitly when we pass the PackageInfo object off to
1592                     // the Activity Manager to launch the app for backup/restore purposes.
1593                     app = mPackageManager.getApplicationInfoAsUser(pkg.packageName,
1594                             PackageManager.GET_SHARED_LIBRARY_FILES, mUserId);
1595                     pkg.applicationInfo.sharedLibraryFiles = app.sharedLibraryFiles;
1596                     pkg.applicationInfo.sharedLibraryInfos = app.sharedLibraryInfos;
1597                 }
1598             } catch (NameNotFoundException e) {
1599                 packages.remove(a);
1600             }
1601         }
1602         return packages;
1603     }
1604 
1605     /**
1606      * Called from the backup tasks: record that the given app has been successfully backed up at
1607      * least once. This includes both key/value and full-data backups through the transport.
1608      */
logBackupComplete(String packageName)1609     public void logBackupComplete(String packageName) {
1610         if (packageName.equals(PACKAGE_MANAGER_SENTINEL)) return;
1611 
1612         for (String receiver : mConstants.getBackupFinishedNotificationReceivers()) {
1613             final Intent notification = new Intent();
1614             notification.setAction(BACKUP_FINISHED_ACTION);
1615             notification.setPackage(receiver);
1616             notification.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES
1617                     | Intent.FLAG_RECEIVER_FOREGROUND);
1618             notification.putExtra(BACKUP_FINISHED_PACKAGE_EXTRA, packageName);
1619             mContext.sendBroadcastAsUser(notification, UserHandle.of(mUserId));
1620         }
1621 
1622         mProcessedPackagesJournal.addPackage(packageName);
1623     }
1624 
1625     /**
1626      * Persistently record the current and ancestral backup tokens, as well as the set of packages
1627      * with data available in the ancestral dataset.
1628      */
writeRestoreTokens()1629     public void writeRestoreTokens() {
1630         try (RandomAccessFile af = new RandomAccessFile(mTokenFile, "rwd")) {
1631             // First, the version number of this record, for futureproofing
1632             af.writeInt(CURRENT_ANCESTRAL_RECORD_VERSION);
1633 
1634             // Write the ancestral and current tokens
1635             af.writeLong(mAncestralToken);
1636             af.writeLong(mCurrentToken);
1637 
1638             // Now write the set of ancestral packages
1639             if (mAncestralPackages == null) {
1640                 af.writeInt(-1);
1641             } else {
1642                 af.writeInt(mAncestralPackages.size());
1643                 if (DEBUG) {
1644                     Slog.v(
1645                             TAG,
1646                             addUserIdToLogMessage(
1647                                     mUserId, "Ancestral packages:  " + mAncestralPackages.size()));
1648                 }
1649                 for (String pkgName : mAncestralPackages) {
1650                     af.writeUTF(pkgName);
1651                     if (MORE_DEBUG) Slog.v(TAG, addUserIdToLogMessage(mUserId, "   " + pkgName));
1652                 }
1653             }
1654         } catch (IOException e) {
1655             Slog.w(TAG, addUserIdToLogMessage(mUserId, "Unable to write token file:"), e);
1656         }
1657     }
1658 
1659     /** Fires off a backup agent, blocking until it attaches or times out. */
1660     @Nullable
bindToAgentSynchronous(ApplicationInfo app, int mode, @OperationType int operationType)1661     public IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode,
1662             @OperationType int operationType) {
1663         IBackupAgent agent = null;
1664         synchronized (mAgentConnectLock) {
1665             mConnecting = true;
1666             mConnectedAgent = null;
1667             try {
1668                 if (mActivityManager.bindBackupAgent(app.packageName, mode, mUserId,
1669                         operationType)) {
1670                     Slog.d(TAG, addUserIdToLogMessage(mUserId, "awaiting agent for " + app));
1671 
1672                     // success; wait for the agent to arrive
1673                     // only wait 10 seconds for the bind to happen
1674                     long timeoutMark = System.currentTimeMillis() + BIND_TIMEOUT_INTERVAL;
1675                     while (mConnecting && mConnectedAgent == null
1676                             && (System.currentTimeMillis() < timeoutMark)) {
1677                         try {
1678                             mAgentConnectLock.wait(5000);
1679                         } catch (InterruptedException e) {
1680                             // just bail
1681                             Slog.w(TAG, addUserIdToLogMessage(mUserId, "Interrupted: " + e));
1682                             mConnecting = false;
1683                             mConnectedAgent = null;
1684                         }
1685                     }
1686 
1687                     // if we timed out with no connect, abort and move on
1688                     if (mConnecting) {
1689                         Slog.w(
1690                                 TAG,
1691                                 addUserIdToLogMessage(mUserId, "Timeout waiting for agent " + app));
1692                         mConnectedAgent = null;
1693                     }
1694                     if (DEBUG) {
1695                         Slog.i(TAG, addUserIdToLogMessage(mUserId, "got agent " + mConnectedAgent));
1696                     }
1697                     agent = mConnectedAgent;
1698                 }
1699             } catch (RemoteException e) {
1700                 // can't happen - ActivityManager is local
1701             }
1702         }
1703         if (agent == null) {
1704             mActivityManagerInternal.clearPendingBackup(mUserId);
1705         }
1706         return agent;
1707     }
1708 
1709     /** Unbind from a backup agent. */
unbindAgent(ApplicationInfo app)1710     public void unbindAgent(ApplicationInfo app) {
1711         try {
1712             mActivityManager.unbindBackupAgent(app);
1713         } catch (RemoteException e) {
1714             // Can't happen - activity manager is local
1715         }
1716     }
1717 
1718     /**
1719      * Clear an application's data after a failed restore, blocking until the operation completes or
1720      * times out.
1721      */
clearApplicationDataAfterRestoreFailure(String packageName)1722     public void clearApplicationDataAfterRestoreFailure(String packageName) {
1723         clearApplicationDataSynchronous(packageName, true, false);
1724     }
1725 
1726     /**
1727      * Clear an application's data before restore, blocking until the operation completes or times
1728      * out.
1729      */
clearApplicationDataBeforeRestore(String packageName)1730     public void clearApplicationDataBeforeRestore(String packageName) {
1731         clearApplicationDataSynchronous(packageName, false, true);
1732     }
1733 
1734     /**
1735      * Clear an application's data, blocking until the operation completes or times out.
1736      *
1737      * @param checkFlagAllowClearUserDataOnFailedRestore if {@code true} uses
1738      *    {@link ApplicationInfo#PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE} to decide if
1739      *    clearing data is allowed after a failed restore.
1740      *
1741      * @param keepSystemState if {@code true}, we don't clear system state such as already restored
1742      *    notification settings, permission grants, etc.
1743      */
clearApplicationDataSynchronous(String packageName, boolean checkFlagAllowClearUserDataOnFailedRestore, boolean keepSystemState)1744     private void clearApplicationDataSynchronous(String packageName,
1745             boolean checkFlagAllowClearUserDataOnFailedRestore, boolean keepSystemState) {
1746         try {
1747             ApplicationInfo applicationInfo = mPackageManager.getPackageInfoAsUser(
1748                     packageName, 0, mUserId).applicationInfo;
1749 
1750             boolean shouldClearData;
1751             if (checkFlagAllowClearUserDataOnFailedRestore
1752                     && applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q) {
1753                 shouldClearData = (applicationInfo.privateFlags
1754                     & ApplicationInfo.PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE) != 0;
1755             } else {
1756                 shouldClearData =
1757                     (applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA) != 0;
1758             }
1759 
1760             if (!shouldClearData) {
1761                 if (MORE_DEBUG) {
1762                     Slog.i(
1763                             TAG,
1764                             addUserIdToLogMessage(
1765                                     mUserId,
1766                                     "Clearing app data is not allowed so not wiping "
1767                                             + packageName));
1768                 }
1769                 return;
1770             }
1771         } catch (NameNotFoundException e) {
1772             Slog.w(
1773                     TAG,
1774                     addUserIdToLogMessage(
1775                             mUserId, "Tried to clear data for " + packageName + " but not found"));
1776             return;
1777         }
1778 
1779         ClearDataObserver observer = new ClearDataObserver(this);
1780 
1781         synchronized (mClearDataLock) {
1782             mClearingData = true;
1783             try {
1784                 mActivityManager.clearApplicationUserData(packageName, keepSystemState, observer,
1785                         mUserId);
1786             } catch (RemoteException e) {
1787                 // can't happen because the activity manager is in this process
1788             }
1789 
1790             // Only wait 30 seconds for the clear data to happen.
1791             long timeoutMark = System.currentTimeMillis() + CLEAR_DATA_TIMEOUT_INTERVAL;
1792             while (mClearingData && (System.currentTimeMillis() < timeoutMark)) {
1793                 try {
1794                     mClearDataLock.wait(5000);
1795                 } catch (InterruptedException e) {
1796                     // won't happen, but still.
1797                     mClearingData = false;
1798                     Slog.w(
1799                             TAG,
1800                             addUserIdToLogMessage(
1801                                     mUserId,
1802                                     "Interrupted while waiting for "
1803                                             + packageName
1804                                             + " data to be cleared"),
1805                             e);
1806                 }
1807             }
1808 
1809             if (mClearingData) {
1810                 Slog.w(
1811                         TAG,
1812                         addUserIdToLogMessage(
1813                                 mUserId, "Clearing app data for " + packageName + " timed out"));
1814             }
1815         }
1816     }
1817 
getEligibilityRulesForRestoreAtInstall(long restoreToken)1818     private BackupEligibilityRules getEligibilityRulesForRestoreAtInstall(long restoreToken) {
1819         if (mAncestralOperationType == OperationType.MIGRATION && restoreToken == mAncestralToken) {
1820             return getEligibilityRulesForOperation(OperationType.MIGRATION);
1821         } else {
1822             // If we're not using the ancestral data set, it means we're restoring from a backup
1823             // that happened on this device.
1824             return mScheduledBackupEligibility;
1825         }
1826     }
1827 
1828     /**
1829      * Get the restore-set token for the best-available restore set for this {@code packageName}:
1830      * the active set if possible, else the ancestral one. Returns zero if none available.
1831      */
getAvailableRestoreToken(String packageName)1832     public long getAvailableRestoreToken(String packageName) {
1833         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
1834                 "getAvailableRestoreToken");
1835 
1836         long token = mAncestralToken;
1837         synchronized (mQueueLock) {
1838             if (mCurrentToken != 0 && mProcessedPackagesJournal.hasBeenProcessed(packageName)) {
1839                 if (MORE_DEBUG) {
1840                     Slog.i(
1841                             TAG,
1842                             addUserIdToLogMessage(
1843                                     mUserId, "App in ever-stored, so using current token"));
1844                 }
1845                 token = mCurrentToken;
1846             }
1847         }
1848         if (MORE_DEBUG) {
1849             Slog.i(TAG, addUserIdToLogMessage(mUserId, "getAvailableRestoreToken() == " + token));
1850         }
1851         return token;
1852     }
1853 
1854     /**
1855      * Requests a backup for the inputted {@code packages}.
1856      *
1857      * @see #requestBackup(String[], IBackupObserver, IBackupManagerMonitor, int).
1858      */
requestBackup(String[] packages, IBackupObserver observer, int flags)1859     public int requestBackup(String[] packages, IBackupObserver observer, int flags) {
1860         return requestBackup(packages, observer, null, flags);
1861     }
1862 
1863     /**
1864      * Requests a backup for the inputted {@code packages} with a specified {@link
1865      * IBackupManagerMonitor} and {@link OperationType}.
1866      */
requestBackup(String[] packages, IBackupObserver observer, IBackupManagerMonitor monitor, int flags)1867     public int requestBackup(String[] packages, IBackupObserver observer,
1868             IBackupManagerMonitor monitor, int flags) {
1869         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "requestBackup");
1870 
1871         if (packages == null || packages.length < 1) {
1872             Slog.e(TAG, addUserIdToLogMessage(mUserId, "No packages named for backup request"));
1873             BackupObserverUtils.sendBackupFinished(observer, BackupManager.ERROR_TRANSPORT_ABORTED);
1874             monitor = BackupManagerMonitorUtils.monitorEvent(monitor,
1875                     BackupManagerMonitor.LOG_EVENT_ID_NO_PACKAGES,
1876                     null, BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT, null);
1877             throw new IllegalArgumentException("No packages are provided for backup");
1878         }
1879 
1880         if (!mEnabled || !mSetupComplete) {
1881             Slog.i(
1882                     TAG,
1883                     addUserIdToLogMessage(mUserId, "Backup requested but enabled="
1884                             + mEnabled
1885                             + " setupComplete="
1886                             + mSetupComplete));
1887             BackupObserverUtils.sendBackupFinished(observer,
1888                     BackupManager.ERROR_BACKUP_NOT_ALLOWED);
1889             final int logTag = mSetupComplete
1890                     ? BackupManagerMonitor.LOG_EVENT_ID_BACKUP_DISABLED
1891                     : BackupManagerMonitor.LOG_EVENT_ID_DEVICE_NOT_PROVISIONED;
1892             monitor = BackupManagerMonitorUtils.monitorEvent(monitor, logTag, null,
1893                     BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, null);
1894             return BackupManager.ERROR_BACKUP_NOT_ALLOWED;
1895         }
1896 
1897         final TransportClient transportClient;
1898         final String transportDirName;
1899         int operationType;
1900         try {
1901             transportDirName =
1902                     mTransportManager.getTransportDirName(
1903                             mTransportManager.getCurrentTransportName());
1904             transportClient =
1905                     mTransportManager.getCurrentTransportClientOrThrow("BMS.requestBackup()");
1906             operationType = getOperationTypeFromTransport(transportClient);
1907         } catch (TransportNotRegisteredException | TransportNotAvailableException
1908                 | RemoteException e) {
1909             BackupObserverUtils.sendBackupFinished(observer, BackupManager.ERROR_TRANSPORT_ABORTED);
1910             monitor = BackupManagerMonitorUtils.monitorEvent(monitor,
1911                     BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_IS_NULL,
1912                     null, BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT, null);
1913             return BackupManager.ERROR_TRANSPORT_ABORTED;
1914         }
1915 
1916         OnTaskFinishedListener listener =
1917                 caller -> mTransportManager.disposeOfTransportClient(transportClient, caller);
1918         BackupEligibilityRules backupEligibilityRules = getEligibilityRulesForOperation(
1919                 operationType);
1920 
1921         Message msg = mBackupHandler.obtainMessage(MSG_REQUEST_BACKUP);
1922         msg.obj = getRequestBackupParams(packages, observer, monitor, flags, backupEligibilityRules,
1923                 transportClient, transportDirName, listener);
1924         mBackupHandler.sendMessage(msg);
1925         return BackupManager.SUCCESS;
1926     }
1927 
1928     @VisibleForTesting
getRequestBackupParams(String[] packages, IBackupObserver observer, IBackupManagerMonitor monitor, int flags, BackupEligibilityRules backupEligibilityRules, TransportClient transportClient, String transportDirName, OnTaskFinishedListener listener)1929     BackupParams getRequestBackupParams(String[] packages, IBackupObserver observer,
1930             IBackupManagerMonitor monitor, int flags, BackupEligibilityRules backupEligibilityRules,
1931             TransportClient transportClient, String transportDirName,
1932             OnTaskFinishedListener listener) {
1933         ArrayList<String> fullBackupList = new ArrayList<>();
1934         ArrayList<String> kvBackupList = new ArrayList<>();
1935         for (String packageName : packages) {
1936             if (PACKAGE_MANAGER_SENTINEL.equals(packageName)) {
1937                 kvBackupList.add(packageName);
1938                 continue;
1939             }
1940             try {
1941                 PackageInfo packageInfo = mPackageManager.getPackageInfoAsUser(packageName,
1942                         PackageManager.GET_SIGNING_CERTIFICATES, mUserId);
1943                 if (!backupEligibilityRules.appIsEligibleForBackup(packageInfo.applicationInfo)) {
1944                     BackupObserverUtils.sendBackupOnPackageResult(observer, packageName,
1945                             BackupManager.ERROR_BACKUP_NOT_ALLOWED);
1946                     continue;
1947                 }
1948                 if (backupEligibilityRules.appGetsFullBackup(packageInfo)) {
1949                     fullBackupList.add(packageInfo.packageName);
1950                 } else {
1951                     kvBackupList.add(packageInfo.packageName);
1952                 }
1953             } catch (NameNotFoundException e) {
1954                 BackupObserverUtils.sendBackupOnPackageResult(observer, packageName,
1955                         BackupManager.ERROR_PACKAGE_NOT_FOUND);
1956             }
1957         }
1958 
1959         EventLog.writeEvent(EventLogTags.BACKUP_REQUESTED, packages.length, kvBackupList.size(),
1960                 fullBackupList.size());
1961         if (MORE_DEBUG) {
1962             Slog.i(
1963                     TAG,
1964                     addUserIdToLogMessage(
1965                             mUserId,
1966                             "Backup requested for "
1967                                     + packages.length
1968                                     + " packages, of them: "
1969                                     + fullBackupList.size()
1970                                     + " full backups, "
1971                                     + kvBackupList.size()
1972                                     + " k/v backups"));
1973         }
1974 
1975         boolean nonIncrementalBackup = (flags & BackupManager.FLAG_NON_INCREMENTAL_BACKUP) != 0;
1976 
1977         return new BackupParams(transportClient, transportDirName, kvBackupList, fullBackupList,
1978                 observer, monitor, listener, /* userInitiated */ true, nonIncrementalBackup,
1979                 backupEligibilityRules);
1980     }
1981 
1982     /** Cancel all running backups. */
cancelBackups()1983     public void cancelBackups() {
1984         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "cancelBackups");
1985         if (MORE_DEBUG) {
1986             Slog.i(TAG, addUserIdToLogMessage(mUserId, "cancelBackups() called."));
1987         }
1988         final long oldToken = Binder.clearCallingIdentity();
1989         try {
1990             List<Integer> operationsToCancel = new ArrayList<>();
1991             synchronized (mCurrentOpLock) {
1992                 for (int i = 0; i < mCurrentOperations.size(); i++) {
1993                     Operation op = mCurrentOperations.valueAt(i);
1994                     int token = mCurrentOperations.keyAt(i);
1995                     if (op.type == OP_TYPE_BACKUP) {
1996                         operationsToCancel.add(token);
1997                     }
1998                 }
1999             }
2000             for (Integer token : operationsToCancel) {
2001                 handleCancel(token, true /* cancelAll */);
2002             }
2003             // We don't want the backup jobs to kick in any time soon.
2004             // Reschedules them to run in the distant future.
2005             KeyValueBackupJob.schedule(mUserId, mContext, BUSY_BACKOFF_MIN_MILLIS, mConstants);
2006             FullBackupJob.schedule(mUserId, mContext, 2 * BUSY_BACKOFF_MIN_MILLIS, mConstants);
2007         } finally {
2008             Binder.restoreCallingIdentity(oldToken);
2009         }
2010     }
2011 
2012     /** Schedule a timeout message for the operation identified by {@code token}. */
prepareOperationTimeout(int token, long interval, BackupRestoreTask callback, int operationType)2013     public void prepareOperationTimeout(int token, long interval, BackupRestoreTask callback,
2014             int operationType) {
2015         if (operationType != OP_TYPE_BACKUP_WAIT && operationType != OP_TYPE_RESTORE_WAIT) {
2016             Slog.wtf(
2017                     TAG,
2018                     addUserIdToLogMessage(
2019                             mUserId,
2020                             "prepareOperationTimeout() doesn't support operation "
2021                                     + Integer.toHexString(token)
2022                                     + " of type "
2023                                     + operationType));
2024             return;
2025         }
2026         if (MORE_DEBUG) {
2027             Slog.v(
2028                     TAG,
2029                     addUserIdToLogMessage(
2030                             mUserId,
2031                             "starting timeout: token="
2032                                     + Integer.toHexString(token)
2033                                     + " interval="
2034                                     + interval
2035                                     + " callback="
2036                                     + callback));
2037         }
2038 
2039         synchronized (mCurrentOpLock) {
2040             mCurrentOperations.put(token, new Operation(OP_PENDING, callback, operationType));
2041             Message msg = mBackupHandler.obtainMessage(getMessageIdForOperationType(operationType),
2042                     token, 0, callback);
2043             mBackupHandler.sendMessageDelayed(msg, interval);
2044         }
2045     }
2046 
getMessageIdForOperationType(int operationType)2047     private int getMessageIdForOperationType(int operationType) {
2048         switch (operationType) {
2049             case OP_TYPE_BACKUP_WAIT:
2050                 return MSG_BACKUP_OPERATION_TIMEOUT;
2051             case OP_TYPE_RESTORE_WAIT:
2052                 return MSG_RESTORE_OPERATION_TIMEOUT;
2053             default:
2054                 Slog.wtf(
2055                         TAG,
2056                         addUserIdToLogMessage(
2057                                 mUserId,
2058                                 "getMessageIdForOperationType called on invalid operation type: "
2059                                         + operationType));
2060                 return -1;
2061         }
2062     }
2063 
2064     /**
2065      * Add an operation to the list of currently running operations. Used for cancellation,
2066      * completion and timeout callbacks that act on the operation via the {@code token}.
2067      */
putOperation(int token, Operation operation)2068     public void putOperation(int token, Operation operation) {
2069         if (MORE_DEBUG) {
2070             Slog.d(
2071                     TAG,
2072                     addUserIdToLogMessage(
2073                             mUserId,
2074                             "Adding operation token="
2075                                     + Integer.toHexString(token)
2076                                     + ", operation type="
2077                                     + operation.type));
2078         }
2079         synchronized (mCurrentOpLock) {
2080             mCurrentOperations.put(token, operation);
2081         }
2082     }
2083 
2084     /**
2085      * Remove an operation from the list of currently running operations. An operation is removed
2086      * when it is completed, cancelled, or timed out, and thus no longer running.
2087      */
removeOperation(int token)2088     public void removeOperation(int token) {
2089         if (MORE_DEBUG) {
2090             Slog.d(
2091                     TAG,
2092                     addUserIdToLogMessage(
2093                             mUserId, "Removing operation token=" + Integer.toHexString(token)));
2094         }
2095         synchronized (mCurrentOpLock) {
2096             if (mCurrentOperations.get(token) == null) {
2097                 Slog.w(TAG, addUserIdToLogMessage(mUserId, "Duplicate remove for operation. token="
2098                         + Integer.toHexString(token)));
2099             }
2100             mCurrentOperations.remove(token);
2101         }
2102     }
2103 
2104     /** Block until we received an operation complete message (from the agent or cancellation). */
waitUntilOperationComplete(int token)2105     public boolean waitUntilOperationComplete(int token) {
2106         if (MORE_DEBUG) {
2107             Slog.i(TAG, addUserIdToLogMessage(mUserId, "Blocking until operation complete for "
2108                     + Integer.toHexString(token)));
2109         }
2110         int finalState = OP_PENDING;
2111         Operation op = null;
2112         synchronized (mCurrentOpLock) {
2113             while (true) {
2114                 op = mCurrentOperations.get(token);
2115                 if (op == null) {
2116                     // mysterious disappearance: treat as success with no callback
2117                     break;
2118                 } else {
2119                     if (op.state == OP_PENDING) {
2120                         try {
2121                             mCurrentOpLock.wait();
2122                         } catch (InterruptedException e) {
2123                         }
2124                         // When the wait is notified we loop around and recheck the current state
2125                     } else {
2126                         if (MORE_DEBUG) {
2127                             Slog.d(
2128                                     TAG,
2129                                     addUserIdToLogMessage(
2130                                             mUserId,
2131                                             "Unblocked waiting for operation token="
2132                                                     + Integer.toHexString(token)));
2133                         }
2134                         // No longer pending; we're done
2135                         finalState = op.state;
2136                         break;
2137                     }
2138                 }
2139             }
2140         }
2141 
2142         removeOperation(token);
2143         if (op != null) {
2144             mBackupHandler.removeMessages(getMessageIdForOperationType(op.type));
2145         }
2146         if (MORE_DEBUG) {
2147             Slog.v(TAG, addUserIdToLogMessage(mUserId, "operation " + Integer.toHexString(token)
2148                     + " complete: finalState=" + finalState));
2149         }
2150         return finalState == OP_ACKNOWLEDGED;
2151     }
2152 
2153     /** Cancel the operation associated with {@code token}. */
handleCancel(int token, boolean cancelAll)2154     public void handleCancel(int token, boolean cancelAll) {
2155         // Notify any synchronous waiters
2156         Operation op = null;
2157         synchronized (mCurrentOpLock) {
2158             op = mCurrentOperations.get(token);
2159             if (MORE_DEBUG) {
2160                 if (op == null) {
2161                     Slog.w(
2162                             TAG,
2163                             addUserIdToLogMessage(
2164                                     mUserId,
2165                                     "Cancel of token "
2166                                             + Integer.toHexString(token)
2167                                             + " but no op found"));
2168                 }
2169             }
2170             int state = (op != null) ? op.state : OP_TIMEOUT;
2171             if (state == OP_ACKNOWLEDGED) {
2172                 // The operation finished cleanly, so we have nothing more to do.
2173                 if (DEBUG) {
2174                     Slog.w(TAG, addUserIdToLogMessage(mUserId, "Operation already got an ack."
2175                             + "Should have been removed from mCurrentOperations."));
2176                 }
2177                 op = null;
2178                 mCurrentOperations.delete(token);
2179             } else if (state == OP_PENDING) {
2180                 if (DEBUG) {
2181                     Slog.v(
2182                             TAG,
2183                             addUserIdToLogMessage(
2184                                     mUserId, "Cancel: token=" + Integer.toHexString(token)));
2185                 }
2186                 op.state = OP_TIMEOUT;
2187                 // Can't delete op from mCurrentOperations here. waitUntilOperationComplete may be
2188                 // called after we receive cancel here. We need this op's state there.
2189 
2190                 // Remove all pending timeout messages of types OP_TYPE_BACKUP_WAIT and
2191                 // OP_TYPE_RESTORE_WAIT. On the other hand, OP_TYPE_BACKUP cannot time out and
2192                 // doesn't require cancellation.
2193                 if (op.type == OP_TYPE_BACKUP_WAIT || op.type == OP_TYPE_RESTORE_WAIT) {
2194                     mBackupHandler.removeMessages(getMessageIdForOperationType(op.type));
2195                 }
2196             }
2197             mCurrentOpLock.notifyAll();
2198         }
2199 
2200         // If there's a TimeoutHandler for this event, call it
2201         if (op != null && op.callback != null) {
2202             if (MORE_DEBUG) {
2203                 Slog.v(TAG, addUserIdToLogMessage(mUserId, "   Invoking cancel on " + op.callback));
2204             }
2205             op.callback.handleCancel(cancelAll);
2206         }
2207     }
2208 
2209     /** Returns {@code true} if a backup is currently running, else returns {@code false}. */
isBackupOperationInProgress()2210     public boolean isBackupOperationInProgress() {
2211         synchronized (mCurrentOpLock) {
2212             for (int i = 0; i < mCurrentOperations.size(); i++) {
2213                 Operation op = mCurrentOperations.valueAt(i);
2214                 if (op.type == OP_TYPE_BACKUP && op.state == OP_PENDING) {
2215                     return true;
2216                 }
2217             }
2218         }
2219         return false;
2220     }
2221 
2222     /** Unbind the backup agent and kill the app if it's a non-system app. */
tearDownAgentAndKill(ApplicationInfo app)2223     public void tearDownAgentAndKill(ApplicationInfo app) {
2224         if (app == null) {
2225             // Null means the system package, so just quietly move on.  :)
2226             return;
2227         }
2228 
2229         try {
2230             // unbind and tidy up even on timeout or failure, just in case
2231             mActivityManager.unbindBackupAgent(app);
2232 
2233             // The agent was running with a stub Application object, so shut it down.
2234             // !!! We hardcode the confirmation UI's package name here rather than use a
2235             //     manifest flag!  TODO something less direct.
2236             if (!UserHandle.isCore(app.uid)
2237                     && !app.packageName.equals("com.android.backupconfirm")) {
2238                 if (MORE_DEBUG) {
2239                     Slog.d(TAG, addUserIdToLogMessage(mUserId, "Killing agent host process"));
2240                 }
2241                 mActivityManager.killApplicationProcess(app.processName, app.uid);
2242             } else {
2243                 if (MORE_DEBUG) {
2244                     Slog.d(
2245                             TAG,
2246                             addUserIdToLogMessage(
2247                                     mUserId, "Not killing after operation: " + app.processName));
2248                 }
2249             }
2250         } catch (RemoteException e) {
2251             Slog.d(TAG, addUserIdToLogMessage(mUserId, "Lost app trying to shut down"));
2252         }
2253     }
2254 
2255     /** For adb backup/restore. */
deviceIsEncrypted()2256     public boolean deviceIsEncrypted() {
2257         try {
2258             return mStorageManager.getEncryptionState()
2259                     != StorageManager.ENCRYPTION_STATE_NONE
2260                     && mStorageManager.getPasswordType()
2261                     != StorageManager.CRYPT_TYPE_DEFAULT;
2262         } catch (Exception e) {
2263             // If we can't talk to the storagemanager service we have a serious problem; fail
2264             // "secure" i.e. assuming that the device is encrypted.
2265             Slog.e(
2266                     TAG,
2267                     addUserIdToLogMessage(
2268                             mUserId,
2269                             "Unable to communicate with storagemanager service: "
2270                                     + e.getMessage()));
2271             return true;
2272         }
2273     }
2274 
2275     // ----- Full-data backup scheduling -----
2276 
2277     /**
2278      * Schedule a job to tell us when it's a good time to run a full backup
2279      */
scheduleNextFullBackupJob(long transportMinLatency)2280     public void scheduleNextFullBackupJob(long transportMinLatency) {
2281         synchronized (mQueueLock) {
2282             if (mFullBackupQueue.size() > 0) {
2283                 // schedule the next job at the point in the future when the least-recently
2284                 // backed up app comes due for backup again; or immediately if it's already
2285                 // due.
2286                 final long upcomingLastBackup = mFullBackupQueue.get(0).lastBackup;
2287                 final long timeSinceLast = System.currentTimeMillis() - upcomingLastBackup;
2288                 final long interval = mConstants.getFullBackupIntervalMilliseconds();
2289                 final long appLatency = (timeSinceLast < interval) ? (interval - timeSinceLast) : 0;
2290                 final long latency = Math.max(transportMinLatency, appLatency);
2291                 FullBackupJob.schedule(mUserId, mContext, latency, mConstants);
2292             } else {
2293                 if (DEBUG_SCHEDULING) {
2294                     Slog.i(
2295                             TAG,
2296                             addUserIdToLogMessage(
2297                                     mUserId, "Full backup queue empty; not scheduling"));
2298                 }
2299             }
2300         }
2301     }
2302 
2303     /**
2304      * Remove a package from the full-data queue.
2305      */
2306     @GuardedBy("mQueueLock")
dequeueFullBackupLocked(String packageName)2307     private void dequeueFullBackupLocked(String packageName) {
2308         final int numPackages = mFullBackupQueue.size();
2309         for (int i = numPackages - 1; i >= 0; i--) {
2310             final FullBackupEntry e = mFullBackupQueue.get(i);
2311             if (packageName.equals(e.packageName)) {
2312                 mFullBackupQueue.remove(i);
2313             }
2314         }
2315     }
2316 
2317     /**
2318      * Enqueue full backup for the given app, with a note about when it last ran.
2319      */
enqueueFullBackup(String packageName, long lastBackedUp)2320     public void enqueueFullBackup(String packageName, long lastBackedUp) {
2321         FullBackupEntry newEntry = new FullBackupEntry(packageName, lastBackedUp);
2322         synchronized (mQueueLock) {
2323             // First, check that we aren't adding a duplicate.  Slow but
2324             // straightforward; we'll have at most on the order of a few hundred
2325             // items in this list.
2326             dequeueFullBackupLocked(packageName);
2327 
2328             // This is also slow but easy for modest numbers of apps: work backwards
2329             // from the end of the queue until we find an item whose last backup
2330             // time was before this one, then insert this new entry after it.  If we're
2331             // adding something new we don't bother scanning, and just prepend.
2332             int which = -1;
2333             if (lastBackedUp > 0) {
2334                 for (which = mFullBackupQueue.size() - 1; which >= 0; which--) {
2335                     final FullBackupEntry entry = mFullBackupQueue.get(which);
2336                     if (entry.lastBackup <= lastBackedUp) {
2337                         mFullBackupQueue.add(which + 1, newEntry);
2338                         break;
2339                     }
2340                 }
2341             }
2342             if (which < 0) {
2343                 // this one is earlier than any existing one, so prepend
2344                 mFullBackupQueue.add(0, newEntry);
2345             }
2346         }
2347         writeFullBackupScheduleAsync();
2348     }
2349 
fullBackupAllowable(String transportName)2350     private boolean fullBackupAllowable(String transportName) {
2351         if (!mTransportManager.isTransportRegistered(transportName)) {
2352             Slog.w(
2353                     TAG,
2354                     addUserIdToLogMessage(
2355                             mUserId, "Transport not registered; full data backup not performed"));
2356             return false;
2357         }
2358 
2359         // Don't proceed unless we have already established package metadata
2360         // for the current dataset via a key/value backup pass.
2361         try {
2362             String transportDirName = mTransportManager.getTransportDirName(transportName);
2363             File stateDir = new File(mBaseStateDir, transportDirName);
2364             File pmState = new File(stateDir, PACKAGE_MANAGER_SENTINEL);
2365             if (pmState.length() <= 0) {
2366                 if (DEBUG) {
2367                     Slog.i(
2368                             TAG,
2369                             addUserIdToLogMessage(
2370                                     mUserId,
2371                                     "Full backup requested but dataset not yet initialized"));
2372                 }
2373                 return false;
2374             }
2375         } catch (Exception e) {
2376             Slog.w(
2377                     TAG,
2378                     addUserIdToLogMessage(
2379                             mUserId, "Unable to get transport name: " + e.getMessage()));
2380             return false;
2381         }
2382 
2383         return true;
2384     }
2385 
2386     /**
2387      * Conditions are right for a full backup operation, so run one.  The model we use is
2388      * to perform one app backup per scheduled job execution, and to reschedule the job
2389      * with zero latency as long as conditions remain right and we still have work to do.
2390      *
2391      * <p>This is the "start a full backup operation" entry point called by the scheduled job.
2392      *
2393      * @return Whether ongoing work will continue.  The return value here will be passed
2394      * along as the return value to the scheduled job's onStartJob() callback.
2395      */
beginFullBackup(FullBackupJob scheduledJob)2396     public boolean beginFullBackup(FullBackupJob scheduledJob) {
2397         final long now = System.currentTimeMillis();
2398         final long fullBackupInterval;
2399         final long keyValueBackupInterval;
2400         synchronized (mConstants) {
2401             fullBackupInterval = mConstants.getFullBackupIntervalMilliseconds();
2402             keyValueBackupInterval = mConstants.getKeyValueBackupIntervalMilliseconds();
2403         }
2404         FullBackupEntry entry = null;
2405         long latency = fullBackupInterval;
2406 
2407         if (!mEnabled || !mSetupComplete) {
2408             // Backups are globally disabled, so don't proceed.  We also don't reschedule
2409             // the job driving automatic backups; that job will be scheduled again when
2410             // the user enables backup.
2411             if (MORE_DEBUG) {
2412                 Slog.i(TAG, addUserIdToLogMessage(mUserId, "beginFullBackup but enabled=" + mEnabled
2413                         + " setupComplete=" + mSetupComplete + "; ignoring"));
2414             }
2415             return false;
2416         }
2417 
2418         // Don't run the backup if we're in battery saver mode, but reschedule
2419         // to try again in the not-so-distant future.
2420         final PowerSaveState result =
2421                 mPowerManager.getPowerSaveState(ServiceType.FULL_BACKUP);
2422         if (result.batterySaverEnabled) {
2423             if (DEBUG) {
2424                 Slog.i(
2425                         TAG,
2426                         addUserIdToLogMessage(
2427                                 mUserId, "Deferring scheduled full backups in battery saver mode"));
2428             }
2429             FullBackupJob.schedule(mUserId, mContext, keyValueBackupInterval, mConstants);
2430             return false;
2431         }
2432 
2433         if (DEBUG_SCHEDULING) {
2434             Slog.i(
2435                     TAG,
2436                     addUserIdToLogMessage(mUserId, "Beginning scheduled full backup operation"));
2437         }
2438 
2439         // Great; we're able to run full backup jobs now.  See if we have any work to do.
2440         synchronized (mQueueLock) {
2441             if (mRunningFullBackupTask != null) {
2442                 Slog.e(
2443                         TAG,
2444                         addUserIdToLogMessage(
2445                                 mUserId, "Backup triggered but one already/still running!"));
2446                 return false;
2447             }
2448 
2449             // At this point we think that we have work to do, but possibly not right now.
2450             // Any exit without actually running backups will also require that we
2451             // reschedule the job.
2452             boolean runBackup = true;
2453             boolean headBusy;
2454 
2455             do {
2456                 // Recheck each time, because culling due to ineligibility may
2457                 // have emptied the queue.
2458                 if (mFullBackupQueue.size() == 0) {
2459                     // no work to do so just bow out
2460                     if (DEBUG) {
2461                         Slog.i(
2462                                 TAG,
2463                                 addUserIdToLogMessage(
2464                                         mUserId, "Backup queue empty; doing nothing"));
2465                     }
2466                     runBackup = false;
2467                     break;
2468                 }
2469 
2470                 headBusy = false;
2471 
2472                 String transportName = mTransportManager.getCurrentTransportName();
2473                 if (!fullBackupAllowable(transportName)) {
2474                     if (MORE_DEBUG) {
2475                         Slog.i(
2476                                 TAG,
2477                                 addUserIdToLogMessage(
2478                                         mUserId, "Preconditions not met; not running full backup"));
2479                     }
2480                     runBackup = false;
2481                     // Typically this means we haven't run a key/value backup yet.  Back off
2482                     // full-backup operations by the key/value job's run interval so that
2483                     // next time we run, we are likely to be able to make progress.
2484                     latency = keyValueBackupInterval;
2485                 }
2486 
2487                 if (runBackup) {
2488                     entry = mFullBackupQueue.get(0);
2489                     long timeSinceRun = now - entry.lastBackup;
2490                     runBackup = (timeSinceRun >= fullBackupInterval);
2491                     if (!runBackup) {
2492                         // It's too early to back up the next thing in the queue, so bow out
2493                         if (MORE_DEBUG) {
2494                             Slog.i(
2495                                     TAG,
2496                                     addUserIdToLogMessage(
2497                                             mUserId,
2498                                             "Device ready but too early to back up next app"));
2499                         }
2500                         // Wait until the next app in the queue falls due for a full data backup
2501                         latency = fullBackupInterval - timeSinceRun;
2502                         break;  // we know we aren't doing work yet, so bail.
2503                     }
2504 
2505                     try {
2506                         PackageInfo appInfo = mPackageManager.getPackageInfoAsUser(
2507                                 entry.packageName, 0, mUserId);
2508                         if (!mScheduledBackupEligibility.appGetsFullBackup(appInfo)) {
2509                             // The head app isn't supposed to get full-data backups [any more];
2510                             // so we cull it and force a loop around to consider the new head
2511                             // app.
2512                             if (MORE_DEBUG) {
2513                                 Slog.i(
2514                                         TAG,
2515                                         addUserIdToLogMessage(
2516                                                 mUserId,
2517                                                 "Culling package "
2518                                                         + entry.packageName
2519                                                         + " in full-backup queue but not"
2520                                                         + " eligible"));
2521                             }
2522                             mFullBackupQueue.remove(0);
2523                             headBusy = true; // force the while() condition
2524                             continue;
2525                         }
2526 
2527                         final int privFlags = appInfo.applicationInfo.privateFlags;
2528                         headBusy = (privFlags & PRIVATE_FLAG_BACKUP_IN_FOREGROUND) == 0
2529                                 && mActivityManagerInternal.isAppForeground(
2530                                         appInfo.applicationInfo.uid);
2531 
2532                         if (headBusy) {
2533                             final long nextEligible = System.currentTimeMillis()
2534                                     + BUSY_BACKOFF_MIN_MILLIS
2535                                     + mTokenGenerator.nextInt(BUSY_BACKOFF_FUZZ);
2536                             if (DEBUG_SCHEDULING) {
2537                                 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
2538                                 Slog.i(
2539                                         TAG,
2540                                         addUserIdToLogMessage(
2541                                                 mUserId,
2542                                                 "Full backup time but "
2543                                                         + entry.packageName
2544                                                         + " is busy; deferring to "
2545                                                         + sdf.format(new Date(nextEligible))));
2546                             }
2547                             // This relocates the app's entry from the head of the queue to
2548                             // its order-appropriate position further down, so upon looping
2549                             // a new candidate will be considered at the head.
2550                             enqueueFullBackup(entry.packageName, nextEligible - fullBackupInterval);
2551                         }
2552                     } catch (NameNotFoundException nnf) {
2553                         // So, we think we want to back this up, but it turns out the package
2554                         // in question is no longer installed.  We want to drop it from the
2555                         // queue entirely and move on, but if there's nothing else in the queue
2556                         // we should bail entirely.  headBusy cannot have been set to true yet.
2557                         runBackup = (mFullBackupQueue.size() > 1);
2558                     }
2559                 }
2560             } while (headBusy);
2561 
2562             if (!runBackup) {
2563                 if (DEBUG_SCHEDULING) {
2564                     Slog.i(
2565                             TAG,
2566                             addUserIdToLogMessage(
2567                                     mUserId,
2568                                     "Nothing pending full backup; rescheduling +" + latency));
2569                 }
2570                 final long deferTime = latency;     // pin for the closure
2571                 FullBackupJob.schedule(mUserId, mContext, deferTime, mConstants);
2572                 return false;
2573             }
2574 
2575             // Okay, the top thing is ready for backup now.  Do it.
2576             mFullBackupQueue.remove(0);
2577             CountDownLatch latch = new CountDownLatch(1);
2578             String[] pkg = new String[]{entry.packageName};
2579             mRunningFullBackupTask = PerformFullTransportBackupTask.newWithCurrentTransport(
2580                     this,
2581                     /* observer */ null,
2582                     pkg,
2583                     /* updateSchedule */ true,
2584                     scheduledJob,
2585                     latch,
2586                     /* backupObserver */ null,
2587                     /* monitor */ null,
2588                     /* userInitiated */ false,
2589                     "BMS.beginFullBackup()",
2590                     getEligibilityRulesForOperation(OperationType.BACKUP));
2591             // Acquiring wakelock for PerformFullTransportBackupTask before its start.
2592             mWakelock.acquire();
2593             (new Thread(mRunningFullBackupTask)).start();
2594         }
2595 
2596         return true;
2597     }
2598 
2599     /**
2600      * The job scheduler says our constraints don't hold anymore, so tear down any ongoing backup
2601      * task right away.
2602      */
endFullBackup()2603     public void endFullBackup() {
2604         // offload the mRunningFullBackupTask.handleCancel() call to another thread,
2605         // as we might have to wait for mCancelLock
2606         Runnable endFullBackupRunnable = new Runnable() {
2607             @Override
2608             public void run() {
2609                 PerformFullTransportBackupTask pftbt = null;
2610                 synchronized (mQueueLock) {
2611                     if (mRunningFullBackupTask != null) {
2612                         pftbt = mRunningFullBackupTask;
2613                     }
2614                 }
2615                 if (pftbt != null) {
2616                     if (DEBUG_SCHEDULING) {
2617                         Slog.i(
2618                                 TAG,
2619                                 addUserIdToLogMessage(
2620                                         mUserId, "Telling running backup to stop"));
2621                     }
2622                     pftbt.handleCancel(true);
2623                 }
2624             }
2625         };
2626         new Thread(endFullBackupRunnable, "end-full-backup").start();
2627     }
2628 
2629     /** Used by both incremental and full restore to restore widget data. */
restoreWidgetData(String packageName, byte[] widgetData)2630     public void restoreWidgetData(String packageName, byte[] widgetData) {
2631         // Apply the restored widget state and generate the ID update for the app
2632         if (MORE_DEBUG) {
2633             Slog.i(TAG, addUserIdToLogMessage(mUserId, "Incorporating restored widget data"));
2634         }
2635         AppWidgetBackupBridge.restoreWidgetState(packageName, widgetData, mUserId);
2636     }
2637 
2638     // *****************************
2639     // NEW UNIFIED RESTORE IMPLEMENTATION
2640     // *****************************
2641 
2642     /** Schedule a backup pass for {@code packageName}. */
dataChangedImpl(String packageName)2643     public void dataChangedImpl(String packageName) {
2644         HashSet<String> targets = dataChangedTargets(packageName);
2645         dataChangedImpl(packageName, targets);
2646     }
2647 
dataChangedImpl(String packageName, HashSet<String> targets)2648     private void dataChangedImpl(String packageName, HashSet<String> targets) {
2649         // Record that we need a backup pass for the caller.  Since multiple callers
2650         // may share a uid, we need to note all candidates within that uid and schedule
2651         // a backup pass for each of them.
2652         if (targets == null) {
2653             Slog.w(
2654                     TAG,
2655                     addUserIdToLogMessage(
2656                             mUserId,
2657                             "dataChanged but no participant pkg='"
2658                                     + packageName
2659                                     + "'"
2660                                     + " uid="
2661                                     + Binder.getCallingUid()));
2662             return;
2663         }
2664 
2665         synchronized (mQueueLock) {
2666             // Note that this client has made data changes that need to be backed up
2667             if (targets.contains(packageName)) {
2668                 // Add the caller to the set of pending backups.  If there is
2669                 // one already there, then overwrite it, but no harm done.
2670                 BackupRequest req = new BackupRequest(packageName);
2671                 if (mPendingBackups.put(packageName, req) == null) {
2672                     if (MORE_DEBUG) {
2673                         Slog.d(
2674                                 TAG,
2675                                 addUserIdToLogMessage(
2676                                         mUserId, "Now staging backup of " + packageName));
2677                     }
2678 
2679                     // Journal this request in case of crash.  The put()
2680                     // operation returned null when this package was not already
2681                     // in the set; we want to avoid touching the disk redundantly.
2682                     writeToJournalLocked(packageName);
2683                 }
2684             }
2685         }
2686 
2687         // ...and schedule a backup pass if necessary
2688         KeyValueBackupJob.schedule(mUserId, mContext, mConstants);
2689     }
2690 
2691     // Note: packageName is currently unused, but may be in the future
dataChangedTargets(String packageName)2692     private HashSet<String> dataChangedTargets(String packageName) {
2693         // If the caller does not hold the BACKUP permission, it can only request a
2694         // backup of its own data.
2695         if ((mContext.checkPermission(android.Manifest.permission.BACKUP, Binder.getCallingPid(),
2696                 Binder.getCallingUid())) == PackageManager.PERMISSION_DENIED) {
2697             synchronized (mBackupParticipants) {
2698                 return mBackupParticipants.get(Binder.getCallingUid());
2699             }
2700         }
2701 
2702         // a caller with full permission can ask to back up any participating app
2703         if (PACKAGE_MANAGER_SENTINEL.equals(packageName)) {
2704             return Sets.newHashSet(PACKAGE_MANAGER_SENTINEL);
2705         } else {
2706             synchronized (mBackupParticipants) {
2707                 return SparseArrayUtils.union(mBackupParticipants);
2708             }
2709         }
2710     }
2711 
writeToJournalLocked(String str)2712     private void writeToJournalLocked(String str) {
2713         try {
2714             if (mJournal == null) mJournal = DataChangedJournal.newJournal(mJournalDir);
2715             mJournal.addPackage(str);
2716         } catch (IOException e) {
2717             Slog.e(
2718                     TAG,
2719                     addUserIdToLogMessage(mUserId, "Can't write " + str + " to backup journal"),
2720                     e);
2721             mJournal = null;
2722         }
2723     }
2724 
2725     // ----- IBackupManager binder interface -----
2726 
2727     /** Sent from an app's backup agent to let the service know that there's new data to backup. */
dataChanged(final String packageName)2728     public void dataChanged(final String packageName) {
2729         final HashSet<String> targets = dataChangedTargets(packageName);
2730         if (targets == null) {
2731             Slog.w(
2732                     TAG,
2733                     addUserIdToLogMessage(
2734                             mUserId,
2735                             "dataChanged but no participant pkg='"
2736                                     + packageName
2737                                     + "'"
2738                                     + " uid="
2739                                     + Binder.getCallingUid()));
2740             return;
2741         }
2742 
2743         mBackupHandler.post(new Runnable() {
2744             public void run() {
2745                 dataChangedImpl(packageName, targets);
2746             }
2747         });
2748     }
2749 
2750     /** Run an initialize operation for the given transport. */
initializeTransports(String[] transportNames, IBackupObserver observer)2751     public void initializeTransports(String[] transportNames, IBackupObserver observer) {
2752         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
2753                 "initializeTransport");
2754         Slog.v(
2755                 TAG,
2756                 addUserIdToLogMessage(
2757                         mUserId, "initializeTransport(): " + Arrays.asList(transportNames)));
2758 
2759         final long oldId = Binder.clearCallingIdentity();
2760         try {
2761             mWakelock.acquire();
2762             OnTaskFinishedListener listener = caller -> mWakelock.release();
2763             mBackupHandler.post(
2764                     new PerformInitializeTask(this, transportNames, observer, listener));
2765         } finally {
2766             Binder.restoreCallingIdentity(oldId);
2767         }
2768     }
2769 
2770     /**
2771      * Sets the work profile serial number of the ancestral work profile.
2772      */
setAncestralSerialNumber(long ancestralSerialNumber)2773     public void setAncestralSerialNumber(long ancestralSerialNumber) {
2774         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP,
2775                 "setAncestralSerialNumber");
2776         Slog.v(
2777                 TAG,
2778                 addUserIdToLogMessage(
2779                         mUserId, "Setting ancestral work profile id to " + ancestralSerialNumber));
2780 
2781         try (RandomAccessFile af =
2782                 new RandomAccessFile(getAncestralSerialNumberFile(), /* mode */ "rwd")) {
2783             af.writeLong(ancestralSerialNumber);
2784         } catch (IOException e) {
2785             Slog.w(
2786                     TAG,
2787                     addUserIdToLogMessage(
2788                             mUserId, "Unable to write to work profile serial mapping file:"),
2789                     e);
2790         }
2791     }
2792 
2793     /**
2794      * Returns the work profile serial number of the ancestral device. This will be set by
2795      * {@link #setAncestralSerialNumber(long)}. Will return {@code -1} if not set.
2796      */
getAncestralSerialNumber()2797     public long getAncestralSerialNumber() {
2798         try (RandomAccessFile af =
2799                 new RandomAccessFile(getAncestralSerialNumberFile(), /* mode */ "r")) {
2800             return af.readLong();
2801         } catch (FileNotFoundException e) {
2802             // It's OK not to have the file present, so we just return -1 to indicate no value.
2803         } catch (IOException e) {
2804             Slog.w(
2805                     TAG,
2806                     addUserIdToLogMessage(
2807                             mUserId, "Unable to read work profile serial number file:"),
2808                     e);
2809         }
2810         return -1;
2811     }
2812 
getAncestralSerialNumberFile()2813     private File getAncestralSerialNumberFile() {
2814         if (mAncestralSerialNumberFile == null) {
2815             mAncestralSerialNumberFile = new File(
2816                 UserBackupManagerFiles.getBaseStateDir(getUserId()),
2817                 SERIAL_ID_FILE);
2818         }
2819         return mAncestralSerialNumberFile;
2820     }
2821 
2822     @VisibleForTesting
setAncestralSerialNumberFile(File ancestralSerialNumberFile)2823     void setAncestralSerialNumberFile(File ancestralSerialNumberFile) {
2824         mAncestralSerialNumberFile = ancestralSerialNumberFile;
2825     }
2826 
2827 
2828     /** Clear the given package's backup data from the current transport. */
clearBackupData(String transportName, String packageName)2829     public void clearBackupData(String transportName, String packageName) {
2830         if (DEBUG) {
2831             Slog.v(
2832                     TAG,
2833                     addUserIdToLogMessage(
2834                             mUserId,
2835                             "clearBackupData() of " + packageName + " on " + transportName));
2836         }
2837 
2838         PackageInfo info;
2839         try {
2840             info = mPackageManager.getPackageInfoAsUser(packageName,
2841                     PackageManager.GET_SIGNING_CERTIFICATES, mUserId);
2842         } catch (NameNotFoundException e) {
2843             Slog.d(
2844                     TAG,
2845                     addUserIdToLogMessage(
2846                             mUserId,
2847                             "No such package '" + packageName + "' - not clearing backup data"));
2848             return;
2849         }
2850 
2851         // If the caller does not hold the BACKUP permission, it can only request a
2852         // wipe of its own backed-up data.
2853         Set<String> apps;
2854         if ((mContext.checkPermission(android.Manifest.permission.BACKUP, Binder.getCallingPid(),
2855                 Binder.getCallingUid())) == PackageManager.PERMISSION_DENIED) {
2856             apps = mBackupParticipants.get(Binder.getCallingUid());
2857         } else {
2858             // a caller with full permission can ask to back up any participating app
2859             // !!! TODO: allow data-clear of ANY app?
2860             if (MORE_DEBUG) {
2861                 Slog.v(
2862                         TAG,
2863                         addUserIdToLogMessage(
2864                                 mUserId, "Privileged caller, allowing clear of other apps"));
2865             }
2866             apps = mProcessedPackagesJournal.getPackagesCopy();
2867         }
2868 
2869         if (apps.contains(packageName)) {
2870             // found it; fire off the clear request
2871             if (MORE_DEBUG) {
2872                 Slog.v(
2873                         TAG,
2874                         addUserIdToLogMessage(mUserId, "Found the app - running clear process"));
2875             }
2876             mBackupHandler.removeMessages(MSG_RETRY_CLEAR);
2877             synchronized (mQueueLock) {
2878                 TransportClient transportClient =
2879                         mTransportManager
2880                                 .getTransportClient(transportName, "BMS.clearBackupData()");
2881                 if (transportClient == null) {
2882                     // transport is currently unregistered -- make sure to retry
2883                     Message msg = mBackupHandler.obtainMessage(MSG_RETRY_CLEAR,
2884                             new ClearRetryParams(transportName, packageName));
2885                     mBackupHandler.sendMessageDelayed(msg, TRANSPORT_RETRY_INTERVAL);
2886                     return;
2887                 }
2888                 final long oldId = Binder.clearCallingIdentity();
2889                 try {
2890                     OnTaskFinishedListener listener = caller -> mTransportManager
2891                             .disposeOfTransportClient(transportClient, caller);
2892                     mWakelock.acquire();
2893                     Message msg = mBackupHandler.obtainMessage(
2894                             MSG_RUN_CLEAR,
2895                             new ClearParams(transportClient, info, listener));
2896                     mBackupHandler.sendMessage(msg);
2897                 } finally {
2898                     Binder.restoreCallingIdentity(oldId);
2899                 }
2900             }
2901         }
2902     }
2903 
2904     /**
2905      * Run a backup pass immediately for any applications that have declared that they have pending
2906      * updates.
2907      */
backupNow()2908     public void backupNow() {
2909         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "backupNow");
2910 
2911         final long oldId = Binder.clearCallingIdentity();
2912         try {
2913             final PowerSaveState result =
2914                     mPowerManager.getPowerSaveState(ServiceType.KEYVALUE_BACKUP);
2915             if (result.batterySaverEnabled) {
2916                 if (DEBUG) {
2917                     Slog.v(
2918                             TAG,
2919                             addUserIdToLogMessage(
2920                                     mUserId, "Not running backup while in battery save mode"));
2921                 }
2922                 // Try again in several hours.
2923                 KeyValueBackupJob.schedule(mUserId, mContext, mConstants);
2924             } else {
2925                 if (DEBUG) {
2926                     Slog.v(TAG, addUserIdToLogMessage(mUserId, "Scheduling immediate backup pass"));
2927                 }
2928 
2929                 synchronized (getQueueLock()) {
2930                     if (getPendingInits().size() > 0) {
2931                         // If there are pending init operations, we process those and then settle
2932                         // into the usual periodic backup schedule.
2933                         if (MORE_DEBUG) {
2934                             Slog.v(
2935                                     TAG,
2936                                     addUserIdToLogMessage(
2937                                             mUserId, "Init pending at scheduled backup"));
2938                         }
2939                         try {
2940                             getAlarmManager().cancel(mRunInitIntent);
2941                             mRunInitIntent.send();
2942                         } catch (PendingIntent.CanceledException ce) {
2943                             Slog.w(
2944                                     TAG,
2945                                     addUserIdToLogMessage(mUserId, "Run init intent cancelled"));
2946                         }
2947                         return;
2948                     }
2949                 }
2950 
2951                 // Don't run backups if we're disabled or not yet set up.
2952                 if (!isEnabled() || !isSetupComplete()) {
2953                     Slog.w(
2954                             TAG,
2955                             addUserIdToLogMessage(mUserId, "Backup pass but enabled="  + isEnabled()
2956                                     + " setupComplete=" + isSetupComplete()));
2957                     return;
2958                 }
2959 
2960                 // Fire the msg that kicks off the whole shebang...
2961                 Message message = mBackupHandler.obtainMessage(MSG_RUN_BACKUP);
2962                 mBackupHandler.sendMessage(message);
2963                 // ...and cancel any pending scheduled job, because we've just superseded it
2964                 KeyValueBackupJob.cancel(mUserId, mContext);
2965             }
2966         } finally {
2967             Binder.restoreCallingIdentity(oldId);
2968         }
2969     }
2970 
2971     /**
2972      * Used by 'adb backup' to run a backup pass for packages supplied via the command line, writing
2973      * the resulting data stream to the supplied {@code fd}. This method is synchronous and does not
2974      * return to the caller until the backup has been completed. It requires on-screen confirmation
2975      * by the user.
2976      */
adbBackup(ParcelFileDescriptor fd, boolean includeApks, boolean includeObbs, boolean includeShared, boolean doWidgets, boolean doAllApps, boolean includeSystem, boolean compress, boolean doKeyValue, String[] pkgList)2977     public void adbBackup(ParcelFileDescriptor fd, boolean includeApks,
2978             boolean includeObbs, boolean includeShared, boolean doWidgets, boolean doAllApps,
2979             boolean includeSystem, boolean compress, boolean doKeyValue, String[] pkgList) {
2980         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "adbBackup");
2981 
2982         final int callingUserHandle = UserHandle.getCallingUserId();
2983         if (callingUserHandle != UserHandle.USER_SYSTEM) {
2984             throw new IllegalStateException("Backup supported only for the device owner");
2985         }
2986 
2987         // Validate
2988         if (!doAllApps) {
2989             if (!includeShared) {
2990                 // If we're backing up shared data (sdcard or equivalent), then we can run
2991                 // without any supplied app names.  Otherwise, we'd be doing no work, so
2992                 // report the error.
2993                 if (pkgList == null || pkgList.length == 0) {
2994                     throw new IllegalArgumentException(
2995                             "Backup requested but neither shared nor any apps named");
2996                 }
2997             }
2998         }
2999 
3000         final long oldId = Binder.clearCallingIdentity();
3001         try {
3002             if (!mSetupComplete) {
3003                 Slog.i(TAG, addUserIdToLogMessage(mUserId, "Backup not supported before setup"));
3004                 return;
3005             }
3006 
3007             if (DEBUG) {
3008                 Slog.v(
3009                         TAG,
3010                         addUserIdToLogMessage(
3011                                 mUserId,
3012                                 "Requesting backup: apks="
3013                                         + includeApks
3014                                         + " obb="
3015                                         + includeObbs
3016                                         + " shared="
3017                                         + includeShared
3018                                         + " all="
3019                                         + doAllApps
3020                                         + " system="
3021                                         + includeSystem
3022                                         + " includekeyvalue="
3023                                         + doKeyValue
3024                                         + " pkgs="
3025                                         + pkgList));
3026             }
3027             Slog.i(TAG, addUserIdToLogMessage(mUserId, "Beginning adb backup..."));
3028 
3029             BackupEligibilityRules eligibilityRules = getEligibilityRulesForOperation(
3030                     OperationType.ADB_BACKUP);
3031             AdbBackupParams params = new AdbBackupParams(fd, includeApks, includeObbs,
3032                     includeShared, doWidgets, doAllApps, includeSystem, compress, doKeyValue,
3033                     pkgList, eligibilityRules);
3034             final int token = generateRandomIntegerToken();
3035             synchronized (mAdbBackupRestoreConfirmations) {
3036                 mAdbBackupRestoreConfirmations.put(token, params);
3037             }
3038 
3039             // start up the confirmation UI
3040             if (DEBUG) {
3041                 Slog.d(
3042                         TAG,
3043                         addUserIdToLogMessage(
3044                                 mUserId, "Starting backup confirmation UI, token=" + token));
3045             }
3046             if (!startConfirmationUi(token, FullBackup.FULL_BACKUP_INTENT_ACTION)) {
3047                 Slog.e(
3048                         TAG,
3049                         addUserIdToLogMessage(mUserId, "Unable to launch backup confirmation UI"));
3050                 mAdbBackupRestoreConfirmations.delete(token);
3051                 return;
3052             }
3053 
3054             // make sure the screen is lit for the user interaction
3055             mPowerManager.userActivity(SystemClock.uptimeMillis(),
3056                     PowerManager.USER_ACTIVITY_EVENT_OTHER,
3057                     0);
3058 
3059             // start the confirmation countdown
3060             startConfirmationTimeout(token, params);
3061 
3062             // wait for the backup to be performed
3063             if (DEBUG) {
3064                 Slog.d(TAG, addUserIdToLogMessage(mUserId, "Waiting for backup completion..."));
3065             }
3066             waitForCompletion(params);
3067         } finally {
3068             try {
3069                 fd.close();
3070             } catch (IOException e) {
3071                 Slog.e(
3072                         TAG,
3073                         addUserIdToLogMessage(
3074                                 mUserId,
3075                                 "IO error closing output for adb backup: " + e.getMessage()));
3076             }
3077             Binder.restoreCallingIdentity(oldId);
3078             Slog.d(TAG, addUserIdToLogMessage(mUserId, "Adb backup processing complete."));
3079         }
3080     }
3081 
3082     /** Run a full backup pass for the given packages. Used by 'adb shell bmgr'. */
fullTransportBackup(String[] pkgNames)3083     public void fullTransportBackup(String[] pkgNames) {
3084         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP,
3085                 "fullTransportBackup");
3086 
3087         final int callingUserHandle = UserHandle.getCallingUserId();
3088         // TODO: http://b/22388012
3089         if (callingUserHandle != UserHandle.USER_SYSTEM) {
3090             throw new IllegalStateException("Restore supported only for the device owner");
3091         }
3092 
3093         String transportName = mTransportManager.getCurrentTransportName();
3094         if (!fullBackupAllowable(transportName)) {
3095             Slog.i(
3096                     TAG,
3097                     addUserIdToLogMessage(
3098                             mUserId,
3099                             "Full backup not currently possible -- key/value backup not yet run?"));
3100         } else {
3101             if (DEBUG) {
3102                 Slog.d(TAG, addUserIdToLogMessage(mUserId, "fullTransportBackup()"));
3103             }
3104 
3105             final long oldId = Binder.clearCallingIdentity();
3106             try {
3107                 CountDownLatch latch = new CountDownLatch(1);
3108                 Runnable task = PerformFullTransportBackupTask.newWithCurrentTransport(
3109                         this,
3110                         /* observer */ null,
3111                         pkgNames,
3112                         /* updateSchedule */ false,
3113                         /* runningJob */ null,
3114                         latch,
3115                         /* backupObserver */ null,
3116                         /* monitor */ null,
3117                         /* userInitiated */ false,
3118                         "BMS.fullTransportBackup()",
3119                         getEligibilityRulesForOperation(OperationType.BACKUP));
3120                 // Acquiring wakelock for PerformFullTransportBackupTask before its start.
3121                 mWakelock.acquire();
3122                 (new Thread(task, "full-transport-master")).start();
3123                 do {
3124                     try {
3125                         latch.await();
3126                         break;
3127                     } catch (InterruptedException e) {
3128                         // Just go back to waiting for the latch to indicate completion
3129                     }
3130                 } while (true);
3131 
3132                 // We just ran a backup on these packages, so kick them to the end of the queue
3133                 final long now = System.currentTimeMillis();
3134                 for (String pkg : pkgNames) {
3135                     enqueueFullBackup(pkg, now);
3136                 }
3137             } finally {
3138                 Binder.restoreCallingIdentity(oldId);
3139             }
3140         }
3141 
3142         if (DEBUG) {
3143             Slog.d(TAG, addUserIdToLogMessage(mUserId, "Done with full transport backup."));
3144         }
3145     }
3146 
3147     /**
3148      * Used by 'adb restore' to run a restore pass, blocking until completion. Requires user
3149      * confirmation.
3150      */
adbRestore(ParcelFileDescriptor fd)3151     public void adbRestore(ParcelFileDescriptor fd) {
3152         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "adbRestore");
3153 
3154         final int callingUserHandle = UserHandle.getCallingUserId();
3155         if (callingUserHandle != UserHandle.USER_SYSTEM) {
3156             throw new IllegalStateException("Restore supported only for the device owner");
3157         }
3158 
3159         final long oldId = Binder.clearCallingIdentity();
3160 
3161         try {
3162             if (!mSetupComplete) {
3163                 Slog.i(
3164                         TAG,
3165                         addUserIdToLogMessage(mUserId, "Full restore not permitted before setup"));
3166                 return;
3167             }
3168 
3169             Slog.i(TAG, addUserIdToLogMessage(mUserId, "Beginning restore..."));
3170 
3171             AdbRestoreParams params = new AdbRestoreParams(fd);
3172             final int token = generateRandomIntegerToken();
3173             synchronized (mAdbBackupRestoreConfirmations) {
3174                 mAdbBackupRestoreConfirmations.put(token, params);
3175             }
3176 
3177             // start up the confirmation UI
3178             if (DEBUG) {
3179                 Slog.d(
3180                         TAG,
3181                         addUserIdToLogMessage(
3182                                 mUserId, "Starting restore confirmation UI, token=" + token));
3183             }
3184             if (!startConfirmationUi(token, FullBackup.FULL_RESTORE_INTENT_ACTION)) {
3185                 Slog.e(
3186                         TAG,
3187                         addUserIdToLogMessage(mUserId, "Unable to launch restore confirmation"));
3188                 mAdbBackupRestoreConfirmations.delete(token);
3189                 return;
3190             }
3191 
3192             // make sure the screen is lit for the user interaction
3193             mPowerManager.userActivity(SystemClock.uptimeMillis(),
3194                     PowerManager.USER_ACTIVITY_EVENT_OTHER,
3195                     0);
3196 
3197             // start the confirmation countdown
3198             startConfirmationTimeout(token, params);
3199 
3200             // wait for the restore to be performed
3201             if (DEBUG) {
3202                 Slog.d(TAG, addUserIdToLogMessage(mUserId, "Waiting for restore completion..."));
3203             }
3204             waitForCompletion(params);
3205         } finally {
3206             try {
3207                 fd.close();
3208             } catch (IOException e) {
3209                 Slog.w(
3210                         TAG,
3211                         addUserIdToLogMessage(
3212                                 mUserId, "Error trying to close fd after adb restore: " + e));
3213             }
3214             Binder.restoreCallingIdentity(oldId);
3215             Slog.i(TAG, addUserIdToLogMessage(mUserId, "adb restore processing complete."));
3216         }
3217     }
3218 
3219     /**
3220      * Excludes keys from KV restore for a given package. The keys won't be part of the data passed
3221      * to the backup agent during restore.
3222      */
excludeKeysFromRestore(String packageName, List<String> keys)3223     public void excludeKeysFromRestore(String packageName, List<String> keys) {
3224         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
3225                 "excludeKeysFromRestore");
3226         mBackupPreferences.addExcludedKeys(packageName, keys);
3227     }
3228 
startConfirmationUi(int token, String action)3229     private boolean startConfirmationUi(int token, String action) {
3230         try {
3231             Intent confIntent = new Intent(action);
3232             confIntent.setClassName("com.android.backupconfirm",
3233                     "com.android.backupconfirm.BackupRestoreConfirmation");
3234             confIntent.putExtra(FullBackup.CONF_TOKEN_INTENT_EXTRA, token);
3235             confIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
3236             mContext.startActivityAsUser(confIntent, UserHandle.SYSTEM);
3237         } catch (ActivityNotFoundException e) {
3238             return false;
3239         }
3240         return true;
3241     }
3242 
startConfirmationTimeout(int token, AdbParams params)3243     private void startConfirmationTimeout(int token, AdbParams params) {
3244         if (MORE_DEBUG) {
3245             Slog.d(TAG, addUserIdToLogMessage(mUserId, "Posting conf timeout msg after "
3246                     + TIMEOUT_FULL_CONFIRMATION + " millis"));
3247         }
3248         Message msg = mBackupHandler.obtainMessage(MSG_FULL_CONFIRMATION_TIMEOUT,
3249                 token, 0, params);
3250         mBackupHandler.sendMessageDelayed(msg, TIMEOUT_FULL_CONFIRMATION);
3251     }
3252 
waitForCompletion(AdbParams params)3253     private void waitForCompletion(AdbParams params) {
3254         synchronized (params.latch) {
3255             while (!params.latch.get()) {
3256                 try {
3257                     params.latch.wait();
3258                 } catch (InterruptedException e) { /* never interrupted */ }
3259             }
3260         }
3261     }
3262 
3263     /** Called when adb backup/restore has completed. */
signalAdbBackupRestoreCompletion(AdbParams params)3264     public void signalAdbBackupRestoreCompletion(AdbParams params) {
3265         synchronized (params.latch) {
3266             params.latch.set(true);
3267             params.latch.notifyAll();
3268         }
3269     }
3270 
3271     /**
3272      * Confirm that the previously-requested full backup/restore operation can proceed. This is used
3273      * to require a user-facing disclosure about the operation.
3274      */
acknowledgeAdbBackupOrRestore(int token, boolean allow, String curPassword, String encPpassword, IFullBackupRestoreObserver observer)3275     public void acknowledgeAdbBackupOrRestore(int token, boolean allow,
3276             String curPassword, String encPpassword, IFullBackupRestoreObserver observer) {
3277         if (DEBUG) {
3278             Slog.d(
3279                     TAG,
3280                     addUserIdToLogMessage(
3281                             mUserId,
3282                             "acknowledgeAdbBackupOrRestore : token=" + token + " allow=" + allow));
3283         }
3284 
3285         // TODO: possibly require not just this signature-only permission, but even
3286         // require that the specific designated confirmation-UI app uid is the caller?
3287         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP,
3288                 "acknowledgeAdbBackupOrRestore");
3289 
3290         final long oldId = Binder.clearCallingIdentity();
3291         try {
3292 
3293             AdbParams params;
3294             synchronized (mAdbBackupRestoreConfirmations) {
3295                 params = mAdbBackupRestoreConfirmations.get(token);
3296                 if (params != null) {
3297                     mBackupHandler.removeMessages(MSG_FULL_CONFIRMATION_TIMEOUT, params);
3298                     mAdbBackupRestoreConfirmations.delete(token);
3299 
3300                     if (allow) {
3301                         final int verb = params instanceof AdbBackupParams
3302                                 ? MSG_RUN_ADB_BACKUP
3303                                 : MSG_RUN_ADB_RESTORE;
3304 
3305                         params.observer = observer;
3306                         params.curPassword = curPassword;
3307 
3308                         params.encryptPassword = encPpassword;
3309 
3310                         if (MORE_DEBUG) {
3311                             Slog.d(
3312                                     TAG,
3313                                     addUserIdToLogMessage(
3314                                             mUserId, "Sending conf message with verb " + verb));
3315                         }
3316                         mWakelock.acquire();
3317                         Message msg = mBackupHandler.obtainMessage(verb, params);
3318                         mBackupHandler.sendMessage(msg);
3319                     } else {
3320                         Slog.w(
3321                                 TAG,
3322                                 addUserIdToLogMessage(
3323                                         mUserId, "User rejected full backup/restore operation"));
3324                         // indicate completion without having actually transferred any data
3325                         signalAdbBackupRestoreCompletion(params);
3326                     }
3327                 } else {
3328                     Slog.w(
3329                             TAG,
3330                             addUserIdToLogMessage(
3331                                     mUserId,
3332                                     "Attempted to ack full backup/restore with invalid token"));
3333                 }
3334             }
3335         } finally {
3336             Binder.restoreCallingIdentity(oldId);
3337         }
3338     }
3339 
3340     /** User-configurable enabling/disabling of backups. */
setBackupEnabled(boolean enable)3341     public void setBackupEnabled(boolean enable) {
3342         setBackupEnabled(enable, /* persistToDisk */ true);
3343     }
3344 
setBackupEnabled(boolean enable, boolean persistToDisk)3345     private void setBackupEnabled(boolean enable, boolean persistToDisk) {
3346         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
3347                 "setBackupEnabled");
3348 
3349         Slog.i(TAG, addUserIdToLogMessage(mUserId, "Backup enabled => " + enable));
3350 
3351         final long oldId = Binder.clearCallingIdentity();
3352         try {
3353             boolean wasEnabled = mEnabled;
3354             synchronized (this) {
3355                 if (persistToDisk) {
3356                     writeEnabledState(enable);
3357                 }
3358                 mEnabled = enable;
3359             }
3360 
3361             updateStateOnBackupEnabled(wasEnabled, enable);
3362         } finally {
3363             Binder.restoreCallingIdentity(oldId);
3364         }
3365     }
3366 
3367     @VisibleForTesting
updateStateOnBackupEnabled(boolean wasEnabled, boolean enable)3368     void updateStateOnBackupEnabled(boolean wasEnabled, boolean enable) {
3369         synchronized (mQueueLock) {
3370             if (enable && !wasEnabled && mSetupComplete) {
3371                 // if we've just been enabled, start scheduling backup passes
3372                 KeyValueBackupJob.schedule(mUserId, mContext, mConstants);
3373                 scheduleNextFullBackupJob(0);
3374             } else if (!enable) {
3375                 // No longer enabled, so stop running backups
3376                 if (MORE_DEBUG) {
3377                     Slog.i(TAG, addUserIdToLogMessage(mUserId, "Opting out of backup"));
3378                 }
3379 
3380                 KeyValueBackupJob.cancel(mUserId, mContext);
3381 
3382                 // This also constitutes an opt-out, so we wipe any data for
3383                 // this device from the backend.  We start that process with
3384                 // an alarm in order to guarantee wakelock states.
3385                 if (wasEnabled && mSetupComplete) {
3386                     // NOTE: we currently flush every registered transport, not just
3387                     // the currently-active one.
3388                     List<String> transportNames = new ArrayList<>();
3389                     List<String> transportDirNames = new ArrayList<>();
3390                     mTransportManager.forEachRegisteredTransport(
3391                             name -> {
3392                                 final String dirName;
3393                                 try {
3394                                     dirName = mTransportManager.getTransportDirName(name);
3395                                 } catch (TransportNotRegisteredException e) {
3396                                     // Should never happen
3397                                     Slog.e(
3398                                             TAG,
3399                                             addUserIdToLogMessage(
3400                                                     mUserId, "Unexpected unregistered transport"),
3401                                             e);
3402                                     return;
3403                                 }
3404                                 transportNames.add(name);
3405                                 transportDirNames.add(dirName);
3406                             });
3407 
3408                     // build the set of transports for which we are posting an init
3409                     for (int i = 0; i < transportNames.size(); i++) {
3410                         recordInitPending(
3411                                 true,
3412                                 transportNames.get(i),
3413                                 transportDirNames.get(i));
3414                     }
3415                     mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
3416                             mRunInitIntent);
3417                 }
3418             }
3419         }
3420     }
3421 
3422     @VisibleForTesting
writeEnabledState(boolean enable)3423     void writeEnabledState(boolean enable) {
3424         UserBackupManagerFilePersistedSettings.writeBackupEnableState(mUserId, enable);
3425     }
3426 
3427     @VisibleForTesting
readEnabledState()3428     boolean readEnabledState() {
3429         return UserBackupManagerFilePersistedSettings.readBackupEnableState(mUserId);
3430     }
3431 
3432     /** Enable/disable automatic restore of app data at install time. */
setAutoRestore(boolean doAutoRestore)3433     public void setAutoRestore(boolean doAutoRestore) {
3434         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
3435                 "setAutoRestore");
3436 
3437         Slog.i(TAG, addUserIdToLogMessage(mUserId, "Auto restore => " + doAutoRestore));
3438 
3439         final long oldId = Binder.clearCallingIdentity();
3440         try {
3441             synchronized (this) {
3442                 Settings.Secure.putIntForUser(mContext.getContentResolver(),
3443                         Settings.Secure.BACKUP_AUTO_RESTORE, doAutoRestore ? 1 : 0, mUserId);
3444                 mAutoRestore = doAutoRestore;
3445             }
3446         } finally {
3447             Binder.restoreCallingIdentity(oldId);
3448         }
3449     }
3450 
3451     /** Report whether the backup mechanism is currently enabled. */
isBackupEnabled()3452     public boolean isBackupEnabled() {
3453         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
3454                 "isBackupEnabled");
3455         return mEnabled;    // no need to synchronize just to read it
3456     }
3457 
3458     /** Report the name of the currently active transport. */
getCurrentTransport()3459     public String getCurrentTransport() {
3460         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
3461                 "getCurrentTransport");
3462         String currentTransport = mTransportManager.getCurrentTransportName();
3463         if (MORE_DEBUG) {
3464             Slog.v(
3465                     TAG,
3466                     addUserIdToLogMessage(
3467                             mUserId, "... getCurrentTransport() returning " + currentTransport));
3468         }
3469         return currentTransport;
3470     }
3471 
3472     /**
3473      * Returns the {@link ComponentName} of the host service of the selected transport or {@code
3474      * null} if no transport selected or if the transport selected is not registered.
3475      */
3476     @Nullable
getCurrentTransportComponent()3477     public ComponentName getCurrentTransportComponent() {
3478         mContext.enforceCallingOrSelfPermission(
3479                 android.Manifest.permission.BACKUP, "getCurrentTransportComponent");
3480         final long oldId = Binder.clearCallingIdentity();
3481         try {
3482             return mTransportManager.getCurrentTransportComponent();
3483         } catch (TransportNotRegisteredException e) {
3484             return null;
3485         } finally {
3486             Binder.restoreCallingIdentity(oldId);
3487         }
3488     }
3489 
3490     /** Report all known, available backup transports by name. */
listAllTransports()3491     public String[] listAllTransports() {
3492         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
3493                 "listAllTransports");
3494 
3495         return mTransportManager.getRegisteredTransportNames();
3496     }
3497 
3498     /** Report all known, available backup transports by component. */
listAllTransportComponents()3499     public ComponentName[] listAllTransportComponents() {
3500         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
3501                 "listAllTransportComponents");
3502         return mTransportManager.getRegisteredTransportComponents();
3503     }
3504 
3505     /**
3506      * Update the attributes of the transport identified by {@code transportComponent}. If the
3507      * specified transport has not been bound at least once (for registration), this call will be
3508      * ignored. Only the host process of the transport can change its description, otherwise a
3509      * {@link SecurityException} will be thrown.
3510      *
3511      * @param transportComponent The identity of the transport being described.
3512      * @param name A {@link String} with the new name for the transport. This is NOT for
3513      *     identification. MUST NOT be {@code null}.
3514      * @param configurationIntent An {@link Intent} that can be passed to
3515      *     {@link Context#startActivity} in order to launch the transport's configuration UI. It may
3516      *     be {@code null} if the transport does not offer any user-facing configuration UI.
3517      * @param currentDestinationString A {@link String} describing the destination to which the
3518      *     transport is currently sending data. MUST NOT be {@code null}.
3519      * @param dataManagementIntent An {@link Intent} that can be passed to
3520      *     {@link Context#startActivity} in order to launch the transport's data-management UI. It
3521      *     may be {@code null} if the transport does not offer any user-facing data
3522      *     management UI.
3523      * @param dataManagementLabel A {@link CharSequence} to be used as the label for the transport's
3524      *     data management affordance. This MUST be {@code null} when dataManagementIntent is
3525      *     {@code null} and MUST NOT be {@code null} when dataManagementIntent is not {@code null}.
3526      * @throws SecurityException If the UID of the calling process differs from the package UID of
3527      *     {@code transportComponent} or if the caller does NOT have BACKUP permission.
3528      */
updateTransportAttributes( ComponentName transportComponent, String name, @Nullable Intent configurationIntent, String currentDestinationString, @Nullable Intent dataManagementIntent, @Nullable CharSequence dataManagementLabel)3529     public void updateTransportAttributes(
3530             ComponentName transportComponent,
3531             String name,
3532             @Nullable Intent configurationIntent,
3533             String currentDestinationString,
3534             @Nullable Intent dataManagementIntent,
3535             @Nullable CharSequence dataManagementLabel) {
3536         updateTransportAttributes(
3537                 Binder.getCallingUid(),
3538                 transportComponent,
3539                 name,
3540                 configurationIntent,
3541                 currentDestinationString,
3542                 dataManagementIntent,
3543                 dataManagementLabel);
3544     }
3545 
3546     @VisibleForTesting
updateTransportAttributes( int callingUid, ComponentName transportComponent, String name, @Nullable Intent configurationIntent, String currentDestinationString, @Nullable Intent dataManagementIntent, @Nullable CharSequence dataManagementLabel)3547     void updateTransportAttributes(
3548             int callingUid,
3549             ComponentName transportComponent,
3550             String name,
3551             @Nullable Intent configurationIntent,
3552             String currentDestinationString,
3553             @Nullable Intent dataManagementIntent,
3554             @Nullable CharSequence dataManagementLabel) {
3555         mContext.enforceCallingOrSelfPermission(
3556                 android.Manifest.permission.BACKUP, "updateTransportAttributes");
3557 
3558         Objects.requireNonNull(transportComponent, "transportComponent can't be null");
3559         Objects.requireNonNull(name, "name can't be null");
3560         Objects.requireNonNull(
3561                 currentDestinationString, "currentDestinationString can't be null");
3562         Preconditions.checkArgument(
3563                 (dataManagementIntent == null) == (dataManagementLabel == null),
3564                 "dataManagementLabel should be null iff dataManagementIntent is null");
3565 
3566         try {
3567             int transportUid =
3568                     mContext.getPackageManager()
3569                             .getPackageUidAsUser(transportComponent.getPackageName(), 0, mUserId);
3570             if (callingUid != transportUid) {
3571                 throw new SecurityException("Only the transport can change its description");
3572             }
3573         } catch (NameNotFoundException e) {
3574             throw new SecurityException("Transport package not found", e);
3575         }
3576 
3577         final long oldId = Binder.clearCallingIdentity();
3578         try {
3579             mTransportManager.updateTransportAttributes(
3580                     transportComponent,
3581                     name,
3582                     configurationIntent,
3583                     currentDestinationString,
3584                     dataManagementIntent,
3585                     dataManagementLabel);
3586         } finally {
3587             Binder.restoreCallingIdentity(oldId);
3588         }
3589     }
3590 
3591     /**
3592      * Selects transport {@code transportName} and returns previously selected transport.
3593      *
3594      * @deprecated Use {@link #selectBackupTransportAsync(ComponentName,
3595      * ISelectBackupTransportCallback)} instead.
3596      */
3597     @Deprecated
3598     @Nullable
selectBackupTransport(String transportName)3599     public String selectBackupTransport(String transportName) {
3600         mContext.enforceCallingOrSelfPermission(
3601                 android.Manifest.permission.BACKUP, "selectBackupTransport");
3602 
3603         final long oldId = Binder.clearCallingIdentity();
3604         try {
3605             String previousTransportName = mTransportManager.selectTransport(transportName);
3606             updateStateForTransport(transportName);
3607             Slog.v(
3608                     TAG,
3609                     addUserIdToLogMessage(
3610                             mUserId,
3611                             "selectBackupTransport(transport = "
3612                                     + transportName
3613                                     + "): previous transport = "
3614                                     + previousTransportName));
3615             return previousTransportName;
3616         } finally {
3617             Binder.restoreCallingIdentity(oldId);
3618         }
3619     }
3620 
3621     /**
3622      * Selects transport {@code transportComponent} asynchronously and notifies {@code listener}
3623      * with the result upon completion.
3624      */
selectBackupTransportAsync( ComponentName transportComponent, ISelectBackupTransportCallback listener)3625     public void selectBackupTransportAsync(
3626             ComponentName transportComponent, ISelectBackupTransportCallback listener) {
3627         mContext.enforceCallingOrSelfPermission(
3628                 android.Manifest.permission.BACKUP, "selectBackupTransportAsync");
3629 
3630         final long oldId = Binder.clearCallingIdentity();
3631         try {
3632             String transportString = transportComponent.flattenToShortString();
3633             Slog.v(
3634                     TAG,
3635                     addUserIdToLogMessage(
3636                             mUserId,
3637                             "selectBackupTransportAsync(transport = " + transportString + ")"));
3638             mBackupHandler.post(
3639                     () -> {
3640                         String transportName = null;
3641                         int result =
3642                                 mTransportManager.registerAndSelectTransport(transportComponent);
3643                         if (result == BackupManager.SUCCESS) {
3644                             try {
3645                                 transportName =
3646                                         mTransportManager.getTransportName(transportComponent);
3647                                 updateStateForTransport(transportName);
3648                             } catch (TransportNotRegisteredException e) {
3649                                 Slog.e(
3650                                         TAG,
3651                                         addUserIdToLogMessage(
3652                                                 mUserId, "Transport got unregistered"));
3653                                 result = BackupManager.ERROR_TRANSPORT_UNAVAILABLE;
3654                             }
3655                         }
3656 
3657                         try {
3658                             if (transportName != null) {
3659                                 listener.onSuccess(transportName);
3660                             } else {
3661                                 listener.onFailure(result);
3662                             }
3663                         } catch (RemoteException e) {
3664                             Slog.e(
3665                                     TAG,
3666                                     addUserIdToLogMessage(
3667                                             mUserId,
3668                                             "ISelectBackupTransportCallback listener not"
3669                                                 + " available"));
3670                         }
3671                     });
3672         } finally {
3673             Binder.restoreCallingIdentity(oldId);
3674         }
3675     }
3676 
3677     /**
3678      * We want to skip backup/restore of certain packages if 'backup_skip_user_facing_packages' is
3679      * set to true in secure settings. See b/153940088 for details.
3680      *
3681      * TODO(b/154822946): Remove this logic in the next release.
3682      */
filterUserFacingPackages(List<PackageInfo> packages)3683     public List<PackageInfo> filterUserFacingPackages(List<PackageInfo> packages) {
3684         if (!shouldSkipUserFacingData()) {
3685             return packages;
3686         }
3687 
3688         List<PackageInfo> filteredPackages = new ArrayList<>(packages.size());
3689         for (PackageInfo packageInfo : packages)  {
3690             if (!shouldSkipPackage(packageInfo.packageName)) {
3691                 filteredPackages.add(packageInfo);
3692             } else {
3693                 Slog.i(TAG, "Will skip backup/restore for " + packageInfo.packageName);
3694             }
3695         }
3696 
3697         return filteredPackages;
3698     }
3699 
3700     @VisibleForTesting
shouldSkipUserFacingData()3701     public boolean shouldSkipUserFacingData() {
3702         return Settings.Secure.getInt(mContext.getContentResolver(), SKIP_USER_FACING_PACKAGES,
3703                 /* def */ 0) != 0;
3704     }
3705 
3706     @VisibleForTesting
shouldSkipPackage(String packageName)3707     public boolean shouldSkipPackage(String packageName) {
3708         return WALLPAPER_PACKAGE.equals(packageName);
3709     }
3710 
updateStateForTransport(String newTransportName)3711     private void updateStateForTransport(String newTransportName) {
3712         // Publish the name change
3713         Settings.Secure.putStringForUser(mContext.getContentResolver(),
3714                 Settings.Secure.BACKUP_TRANSPORT, newTransportName, mUserId);
3715 
3716         // And update our current-dataset bookkeeping
3717         String callerLogString = "BMS.updateStateForTransport()";
3718         TransportClient transportClient =
3719                 mTransportManager.getTransportClient(newTransportName, callerLogString);
3720         if (transportClient != null) {
3721             try {
3722                 IBackupTransport transport = transportClient.connectOrThrow(callerLogString);
3723                 mCurrentToken = transport.getCurrentRestoreSet();
3724             } catch (Exception e) {
3725                 // Oops.  We can't know the current dataset token, so reset and figure it out
3726                 // when we do the next k/v backup operation on this transport.
3727                 mCurrentToken = 0;
3728                 Slog.w(
3729                         TAG,
3730                         addUserIdToLogMessage(
3731                                 mUserId,
3732                                 "Transport "
3733                                         + newTransportName
3734                                         + " not available: current token = 0"));
3735             }
3736             mTransportManager.disposeOfTransportClient(transportClient, callerLogString);
3737         } else {
3738             Slog.w(
3739                     TAG,
3740                     addUserIdToLogMessage(
3741                             mUserId,
3742                             "Transport "
3743                                     + newTransportName
3744                                     + " not registered: current token = 0"));
3745             // The named transport isn't registered, so we can't know what its current dataset token
3746             // is. Reset as above.
3747             mCurrentToken = 0;
3748         }
3749     }
3750 
3751     /**
3752      * Supply the configuration intent for the given transport. If the name is not one of the
3753      * available transports, or if the transport does not supply any configuration UI, the method
3754      * returns {@code null}.
3755      */
getConfigurationIntent(String transportName)3756     public Intent getConfigurationIntent(String transportName) {
3757         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
3758                 "getConfigurationIntent");
3759         try {
3760             Intent intent = mTransportManager.getTransportConfigurationIntent(transportName);
3761             if (MORE_DEBUG) {
3762                 Slog.d(
3763                         TAG,
3764                         addUserIdToLogMessage(
3765                                 mUserId, "getConfigurationIntent() returning intent " + intent));
3766             }
3767             return intent;
3768         } catch (TransportNotRegisteredException e) {
3769             Slog.e(
3770                     TAG,
3771                     addUserIdToLogMessage(
3772                             mUserId,
3773                             "Unable to get configuration intent from transport: "
3774                                     + e.getMessage()));
3775             return null;
3776         }
3777     }
3778 
3779     /**
3780      * Supply the current destination string for the given transport. If the name is not one of the
3781      * registered transports the method will return null.
3782      *
3783      * <p>This string is used VERBATIM as the summary text of the relevant Settings item.
3784      *
3785      * @param transportName The name of the registered transport.
3786      * @return The current destination string or null if the transport is not registered.
3787      */
getDestinationString(String transportName)3788     public String getDestinationString(String transportName) {
3789         mContext.enforceCallingOrSelfPermission(
3790                 android.Manifest.permission.BACKUP, "getDestinationString");
3791 
3792         try {
3793             String string = mTransportManager.getTransportCurrentDestinationString(transportName);
3794             if (MORE_DEBUG) {
3795                 Slog.d(
3796                         TAG,
3797                         addUserIdToLogMessage(
3798                                 mUserId, "getDestinationString() returning " + string));
3799             }
3800             return string;
3801         } catch (TransportNotRegisteredException e) {
3802             Slog.e(
3803                     TAG,
3804                     addUserIdToLogMessage(
3805                             mUserId,
3806                             "Unable to get destination string from transport: " + e.getMessage()));
3807             return null;
3808         }
3809     }
3810 
3811     /** Supply the manage-data intent for the given transport. */
getDataManagementIntent(String transportName)3812     public Intent getDataManagementIntent(String transportName) {
3813         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
3814                 "getDataManagementIntent");
3815 
3816         try {
3817             Intent intent = mTransportManager.getTransportDataManagementIntent(transportName);
3818             if (MORE_DEBUG) {
3819                 Slog.d(
3820                         TAG,
3821                         addUserIdToLogMessage(
3822                                 mUserId, "getDataManagementIntent() returning intent " + intent));
3823             }
3824             return intent;
3825         } catch (TransportNotRegisteredException e) {
3826             Slog.e(
3827                     TAG,
3828                     addUserIdToLogMessage(
3829                             mUserId,
3830                             "Unable to get management intent from transport: " + e.getMessage()));
3831             return null;
3832         }
3833     }
3834 
3835     /**
3836      * Supply the menu label for affordances that fire the manage-data intent for the given
3837      * transport.
3838      */
getDataManagementLabel(String transportName)3839     public CharSequence getDataManagementLabel(String transportName) {
3840         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
3841                 "getDataManagementLabel");
3842 
3843         try {
3844             CharSequence label = mTransportManager.getTransportDataManagementLabel(transportName);
3845             if (MORE_DEBUG) {
3846                 Slog.d(
3847                         TAG,
3848                         addUserIdToLogMessage(
3849                                 mUserId, "getDataManagementLabel() returning " + label));
3850             }
3851             return label;
3852         } catch (TransportNotRegisteredException e) {
3853             Slog.e(
3854                     TAG,
3855                     addUserIdToLogMessage(
3856                             mUserId,
3857                             "Unable to get management label from transport: " + e.getMessage()));
3858             return null;
3859         }
3860     }
3861 
3862     /**
3863      * Callback: a requested backup agent has been instantiated. This should only be called from the
3864      * {@link ActivityManager}.
3865      */
agentConnected(String packageName, IBinder agentBinder)3866     public void agentConnected(String packageName, IBinder agentBinder) {
3867         synchronized (mAgentConnectLock) {
3868             if (Binder.getCallingUid() == Process.SYSTEM_UID) {
3869                 Slog.d(
3870                         TAG,
3871                         addUserIdToLogMessage(
3872                                 mUserId,
3873                                 "agentConnected pkg=" + packageName + " agent=" + agentBinder));
3874                 mConnectedAgent = IBackupAgent.Stub.asInterface(agentBinder);
3875                 mConnecting = false;
3876             } else {
3877                 Slog.w(
3878                         TAG,
3879                         addUserIdToLogMessage(
3880                                 mUserId,
3881                                 "Non-system process uid="
3882                                         + Binder.getCallingUid()
3883                                         + " claiming agent connected"));
3884             }
3885             mAgentConnectLock.notifyAll();
3886         }
3887     }
3888 
3889     /**
3890      * Callback: a backup agent has failed to come up, or has unexpectedly quit. If the agent failed
3891      * to come up in the first place, the agentBinder argument will be {@code null}. This should
3892      * only be called from the {@link ActivityManager}.
3893      */
agentDisconnected(String packageName)3894     public void agentDisconnected(String packageName) {
3895         // TODO: handle backup being interrupted
3896         synchronized (mAgentConnectLock) {
3897             if (Binder.getCallingUid() == Process.SYSTEM_UID) {
3898                 mConnectedAgent = null;
3899                 mConnecting = false;
3900             } else {
3901                 Slog.w(
3902                         TAG,
3903                         addUserIdToLogMessage(
3904                                 mUserId,
3905                                 "Non-system process uid="
3906                                         + Binder.getCallingUid()
3907                                         + " claiming agent disconnected"));
3908             }
3909             mAgentConnectLock.notifyAll();
3910         }
3911     }
3912 
3913     /**
3914      * An application being installed will need a restore pass, then the {@link PackageManager} will
3915      * need to be told when the restore is finished.
3916      */
restoreAtInstall(String packageName, int token)3917     public void restoreAtInstall(String packageName, int token) {
3918         if (Binder.getCallingUid() != Process.SYSTEM_UID) {
3919             Slog.w(
3920                     TAG,
3921                     addUserIdToLogMessage(
3922                             mUserId,
3923                             "Non-system process uid="
3924                                     + Binder.getCallingUid()
3925                                     + " attemping install-time restore"));
3926             return;
3927         }
3928 
3929         boolean skip = false;
3930 
3931         long restoreSet = getAvailableRestoreToken(packageName);
3932         if (DEBUG) {
3933             Slog.v(
3934                     TAG,
3935                     addUserIdToLogMessage(
3936                             mUserId,
3937                             "restoreAtInstall pkg="
3938                                     + packageName
3939                                     + " token="
3940                                     + Integer.toHexString(token)
3941                                     + " restoreSet="
3942                                     + Long.toHexString(restoreSet)));
3943         }
3944         if (restoreSet == 0) {
3945             if (MORE_DEBUG) Slog.i(TAG, addUserIdToLogMessage(mUserId, "No restore set"));
3946             skip = true;
3947         }
3948 
3949         TransportClient transportClient =
3950                 mTransportManager.getCurrentTransportClient("BMS.restoreAtInstall()");
3951         if (transportClient == null) {
3952             if (DEBUG) Slog.w(TAG, addUserIdToLogMessage(mUserId, "No transport client"));
3953             skip = true;
3954         }
3955 
3956         if (!mAutoRestore) {
3957             if (DEBUG) {
3958                 Slog.w(
3959                         TAG,
3960                         addUserIdToLogMessage(
3961                                 mUserId, "Non-restorable state: auto=" + mAutoRestore));
3962             }
3963             skip = true;
3964         }
3965 
3966         if (!skip) {
3967             try {
3968                 // okay, we're going to attempt a restore of this package from this restore set.
3969                 // The eventual message back into the Package Manager to run the post-install
3970                 // steps for 'token' will be issued from the restore handling code.
3971 
3972                 mWakelock.acquire();
3973 
3974                 OnTaskFinishedListener listener = caller -> {
3975                     mTransportManager.disposeOfTransportClient(transportClient, caller);
3976                     mWakelock.release();
3977                 };
3978 
3979                 if (MORE_DEBUG) {
3980                     Slog.d(
3981                             TAG,
3982                             addUserIdToLogMessage(mUserId, "Restore at install of " + packageName));
3983                 }
3984                 Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
3985                 msg.obj =
3986                         RestoreParams.createForRestoreAtInstall(
3987                                 transportClient,
3988                                 /* observer */ null,
3989                                 /* monitor */ null,
3990                                 restoreSet,
3991                                 packageName,
3992                                 token,
3993                                 listener,
3994                                 getEligibilityRulesForRestoreAtInstall(restoreSet));
3995                 mBackupHandler.sendMessage(msg);
3996             } catch (Exception e) {
3997                 // Calling into the transport broke; back off and proceed with the installation.
3998                 Slog.e(
3999                         TAG,
4000                         addUserIdToLogMessage(
4001                                 mUserId, "Unable to contact transport: " + e.getMessage()));
4002                 skip = true;
4003             }
4004         }
4005 
4006         if (skip) {
4007             // Auto-restore disabled or no way to attempt a restore
4008 
4009             if (transportClient != null) {
4010                 mTransportManager.disposeOfTransportClient(
4011                         transportClient, "BMS.restoreAtInstall()");
4012             }
4013 
4014             // Tell the PackageManager to proceed with the post-install handling for this package.
4015             if (DEBUG) Slog.v(TAG, addUserIdToLogMessage(mUserId, "Finishing install immediately"));
4016             try {
4017                 mPackageManagerBinder.finishPackageInstall(token, false);
4018             } catch (RemoteException e) { /* can't happen */ }
4019         }
4020     }
4021 
4022     /** Hand off a restore session. */
beginRestoreSession(String packageName, String transport)4023     public IRestoreSession beginRestoreSession(String packageName, String transport) {
4024         if (DEBUG) {
4025             Slog.v(
4026                     TAG,
4027                     addUserIdToLogMessage(
4028                             mUserId,
4029                             "beginRestoreSession: pkg=" + packageName + " transport=" + transport));
4030         }
4031 
4032         boolean needPermission = true;
4033         if (transport == null) {
4034             transport = mTransportManager.getCurrentTransportName();
4035 
4036             if (packageName != null) {
4037                 PackageInfo app = null;
4038                 try {
4039                     app = mPackageManager.getPackageInfoAsUser(packageName, 0, mUserId);
4040                 } catch (NameNotFoundException nnf) {
4041                     Slog.w(
4042                             TAG,
4043                             addUserIdToLogMessage(
4044                                     mUserId, "Asked to restore nonexistent pkg " + packageName));
4045                     throw new IllegalArgumentException("Package " + packageName + " not found");
4046                 }
4047 
4048                 if (app.applicationInfo.uid == Binder.getCallingUid()) {
4049                     // So: using the current active transport, and the caller has asked
4050                     // that its own package will be restored.  In this narrow use case
4051                     // we do not require the caller to hold the permission.
4052                     needPermission = false;
4053                 }
4054             }
4055         }
4056 
4057         if (needPermission) {
4058             mContext.enforceCallingOrSelfPermission(
4059                     android.Manifest.permission.BACKUP, "beginRestoreSession");
4060         } else {
4061             if (DEBUG) {
4062                 Slog.d(
4063                         TAG,
4064                         addUserIdToLogMessage(
4065                                 mUserId,
4066                                 "restoring self on current transport; no permission needed"));
4067             }
4068         }
4069 
4070         int operationType;
4071         try {
4072             operationType = getOperationTypeFromTransport(
4073                     mTransportManager.getTransportClientOrThrow(transport, /* caller */
4074                             "BMS.beginRestoreSession"));
4075         } catch (TransportNotAvailableException | TransportNotRegisteredException
4076                 | RemoteException e) {
4077             Slog.w(TAG, "Failed to get operation type from transport: " + e);
4078             return null;
4079         }
4080 
4081         synchronized (this) {
4082             if (mActiveRestoreSession != null) {
4083                 Slog.i(
4084                         TAG,
4085                         addUserIdToLogMessage(
4086                                 mUserId, "Restore session requested but one already active"));
4087                 return null;
4088             }
4089             if (mBackupRunning) {
4090                 Slog.i(
4091                         TAG,
4092                         addUserIdToLogMessage(
4093                                 mUserId,
4094                                 "Restore session requested but currently running backups"));
4095                 return null;
4096             }
4097             mActiveRestoreSession = new ActiveRestoreSession(this, packageName, transport,
4098                     getEligibilityRulesForOperation(operationType));
4099             mBackupHandler.sendEmptyMessageDelayed(MSG_RESTORE_SESSION_TIMEOUT,
4100                     mAgentTimeoutParameters.getRestoreSessionTimeoutMillis());
4101         }
4102         return mActiveRestoreSession;
4103     }
4104 
4105     /** Clear the specified restore session. */
clearRestoreSession(ActiveRestoreSession currentSession)4106     public void clearRestoreSession(ActiveRestoreSession currentSession) {
4107         synchronized (this) {
4108             if (currentSession != mActiveRestoreSession) {
4109                 Slog.e(TAG, addUserIdToLogMessage(mUserId, "ending non-current restore session"));
4110             } else {
4111                 if (DEBUG) {
4112                     Slog.v(
4113                             TAG,
4114                             addUserIdToLogMessage(
4115                                     mUserId, "Clearing restore session and halting timeout"));
4116                 }
4117                 mActiveRestoreSession = null;
4118                 mBackupHandler.removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
4119             }
4120         }
4121     }
4122 
4123     /**
4124      * Note that a currently-active backup agent has notified us that it has completed the given
4125      * outstanding asynchronous backup/restore operation.
4126      */
opComplete(int token, long result)4127     public void opComplete(int token, long result) {
4128         if (MORE_DEBUG) {
4129             Slog.v(
4130                     TAG,
4131                     addUserIdToLogMessage(
4132                             mUserId,
4133                             "opComplete: " + Integer.toHexString(token) + " result=" + result));
4134         }
4135         Operation op = null;
4136         synchronized (mCurrentOpLock) {
4137             op = mCurrentOperations.get(token);
4138             if (op != null) {
4139                 if (op.state == OP_TIMEOUT) {
4140                     // The operation already timed out, and this is a late response.  Tidy up
4141                     // and ignore it; we've already dealt with the timeout.
4142                     op = null;
4143                     mCurrentOperations.delete(token);
4144                 } else if (op.state == OP_ACKNOWLEDGED) {
4145                     if (DEBUG) {
4146                         Slog.w(
4147                                 TAG,
4148                                 addUserIdToLogMessage(
4149                                         mUserId,
4150                                         "Received duplicate ack for token="
4151                                                 + Integer.toHexString(token)));
4152                     }
4153                     op = null;
4154                     mCurrentOperations.remove(token);
4155                 } else if (op.state == OP_PENDING) {
4156                     // Can't delete op from mCurrentOperations. waitUntilOperationComplete can be
4157                     // called after we we receive this call.
4158                     op.state = OP_ACKNOWLEDGED;
4159                 }
4160             }
4161             mCurrentOpLock.notifyAll();
4162         }
4163 
4164         // The completion callback, if any, is invoked on the handler
4165         if (op != null && op.callback != null) {
4166             Pair<BackupRestoreTask, Long> callbackAndResult = Pair.create(op.callback, result);
4167             Message msg = mBackupHandler.obtainMessage(MSG_OP_COMPLETE, callbackAndResult);
4168             mBackupHandler.sendMessage(msg);
4169         }
4170     }
4171 
4172     /** Checks if the package is eligible for backup. */
isAppEligibleForBackup(String packageName)4173     public boolean isAppEligibleForBackup(String packageName) {
4174         mContext.enforceCallingOrSelfPermission(
4175                 android.Manifest.permission.BACKUP, "isAppEligibleForBackup");
4176 
4177         final long oldToken = Binder.clearCallingIdentity();
4178         try {
4179             String callerLogString = "BMS.isAppEligibleForBackup";
4180             TransportClient transportClient =
4181                     mTransportManager.getCurrentTransportClient(callerLogString);
4182             boolean eligible =
4183                     mScheduledBackupEligibility.appIsRunningAndEligibleForBackupWithTransport(
4184                             transportClient, packageName);
4185             if (transportClient != null) {
4186                 mTransportManager.disposeOfTransportClient(transportClient, callerLogString);
4187             }
4188             return eligible;
4189         } finally {
4190             Binder.restoreCallingIdentity(oldToken);
4191         }
4192     }
4193 
4194     /** Returns the inputted packages that are eligible for backup. */
filterAppsEligibleForBackup(String[] packages)4195     public String[] filterAppsEligibleForBackup(String[] packages) {
4196         mContext.enforceCallingOrSelfPermission(
4197                 android.Manifest.permission.BACKUP, "filterAppsEligibleForBackup");
4198 
4199         final long oldToken = Binder.clearCallingIdentity();
4200         try {
4201             String callerLogString = "BMS.filterAppsEligibleForBackup";
4202             TransportClient transportClient =
4203                     mTransportManager.getCurrentTransportClient(callerLogString);
4204             List<String> eligibleApps = new LinkedList<>();
4205             for (String packageName : packages) {
4206                 if (mScheduledBackupEligibility.appIsRunningAndEligibleForBackupWithTransport(
4207                                 transportClient, packageName)) {
4208                     eligibleApps.add(packageName);
4209                 }
4210             }
4211             if (transportClient != null) {
4212                 mTransportManager.disposeOfTransportClient(transportClient, callerLogString);
4213             }
4214             return eligibleApps.toArray(new String[eligibleApps.size()]);
4215         } finally {
4216             Binder.restoreCallingIdentity(oldToken);
4217         }
4218     }
4219 
getEligibilityRulesForOperation( @perationType int operationType)4220     public BackupEligibilityRules getEligibilityRulesForOperation(
4221             @OperationType int operationType) {
4222         return getEligibilityRules(mPackageManager, mUserId, operationType);
4223     }
4224 
getEligibilityRules(PackageManager packageManager, int userId, @OperationType int operationType)4225     private static BackupEligibilityRules getEligibilityRules(PackageManager packageManager,
4226             int userId, @OperationType int operationType) {
4227         return new BackupEligibilityRules(packageManager,
4228                 LocalServices.getService(PackageManagerInternal.class), userId, operationType);
4229     }
4230 
4231     /** Prints service state for 'dumpsys backup'. */
dump(FileDescriptor fd, PrintWriter pw, String[] args)4232     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
4233         final long identityToken = Binder.clearCallingIdentity();
4234         try {
4235             if (args != null) {
4236                 for (String arg : args) {
4237                     if ("agents".startsWith(arg)) {
4238                         dumpAgents(pw);
4239                         return;
4240                     } else if ("transportclients".equals(arg.toLowerCase())) {
4241                         mTransportManager.dumpTransportClients(pw);
4242                         return;
4243                     } else if ("transportstats".equals(arg.toLowerCase())) {
4244                         mTransportManager.dumpTransportStats(pw);
4245                         return;
4246                     }
4247                 }
4248             }
4249             dumpInternal(pw);
4250         } finally {
4251             Binder.restoreCallingIdentity(identityToken);
4252         }
4253     }
4254 
dumpAgents(PrintWriter pw)4255     private void dumpAgents(PrintWriter pw) {
4256         List<PackageInfo> agentPackages = allAgentPackages();
4257         pw.println("Defined backup agents:");
4258         for (PackageInfo pkg : agentPackages) {
4259             pw.print("  ");
4260             pw.print(pkg.packageName);
4261             pw.println(':');
4262             pw.print("      ");
4263             pw.println(pkg.applicationInfo.backupAgentName);
4264         }
4265     }
4266 
dumpInternal(PrintWriter pw)4267     private void dumpInternal(PrintWriter pw) {
4268         // Add prefix for only non-system users so that system user dumpsys is the same as before
4269         String userPrefix = mUserId == UserHandle.USER_SYSTEM ? "" : "User " + mUserId + ":";
4270         synchronized (mQueueLock) {
4271             pw.println(userPrefix + "Backup Manager is " + (mEnabled ? "enabled" : "disabled")
4272                     + " / " + (!mSetupComplete ? "not " : "") + "setup complete / "
4273                     + (this.mPendingInits.size() == 0 ? "not " : "") + "pending init");
4274             pw.println("Auto-restore is " + (mAutoRestore ? "enabled" : "disabled"));
4275             if (mBackupRunning) pw.println("Backup currently running");
4276             pw.println(isBackupOperationInProgress() ? "Backup in progress" : "No backups running");
4277             pw.println("Last backup pass started: " + mLastBackupPass
4278                     + " (now = " + System.currentTimeMillis() + ')');
4279             pw.println("  next scheduled: " + KeyValueBackupJob.nextScheduled(mUserId));
4280 
4281             pw.println(userPrefix + "Transport whitelist:");
4282             for (ComponentName transport : mTransportManager.getTransportWhitelist()) {
4283                 pw.print("    ");
4284                 pw.println(transport.flattenToShortString());
4285             }
4286 
4287             pw.println(userPrefix + "Available transports:");
4288             final String[] transports = listAllTransports();
4289             if (transports != null) {
4290                 for (String t : transports) {
4291                     pw.println((t.equals(mTransportManager.getCurrentTransportName()) ? "  * "
4292                             : "    ") + t);
4293                     try {
4294                         File dir = new File(mBaseStateDir,
4295                                 mTransportManager.getTransportDirName(t));
4296                         pw.println("       destination: "
4297                                 + mTransportManager.getTransportCurrentDestinationString(t));
4298                         pw.println("       intent: "
4299                                 + mTransportManager.getTransportConfigurationIntent(t));
4300                         for (File f : dir.listFiles()) {
4301                             pw.println(
4302                                     "       " + f.getName() + " - " + f.length() + " state bytes");
4303                         }
4304                     } catch (Exception e) {
4305                         Slog.e(TAG, addUserIdToLogMessage(mUserId, "Error in transport"), e);
4306                         pw.println("        Error: " + e);
4307                     }
4308                 }
4309             }
4310 
4311             mTransportManager.dumpTransportClients(pw);
4312 
4313             pw.println(userPrefix + "Pending init: " + mPendingInits.size());
4314             for (String s : mPendingInits) {
4315                 pw.println("    " + s);
4316             }
4317 
4318             pw.print(userPrefix + "Ancestral: ");
4319             pw.println(Long.toHexString(mAncestralToken));
4320             pw.print(userPrefix + "Current:   ");
4321             pw.println(Long.toHexString(mCurrentToken));
4322 
4323             int numPackages = mBackupParticipants.size();
4324             pw.println(userPrefix + "Participants:");
4325             for (int i = 0; i < numPackages; i++) {
4326                 int uid = mBackupParticipants.keyAt(i);
4327                 pw.print("  uid: ");
4328                 pw.println(uid);
4329                 HashSet<String> participants = mBackupParticipants.valueAt(i);
4330                 for (String app : participants) {
4331                     pw.println("    " + app);
4332                 }
4333             }
4334 
4335             pw.println(userPrefix + "Ancestral packages: "
4336                     + (mAncestralPackages == null ? "none" : mAncestralPackages.size()));
4337             if (mAncestralPackages != null) {
4338                 for (String pkg : mAncestralPackages) {
4339                     pw.println("    " + pkg);
4340                 }
4341             }
4342 
4343             Set<String> processedPackages = mProcessedPackagesJournal.getPackagesCopy();
4344             pw.println(userPrefix + "Ever backed up: " + processedPackages.size());
4345             for (String pkg : processedPackages) {
4346                 pw.println("    " + pkg);
4347             }
4348 
4349             pw.println(userPrefix + "Pending key/value backup: " + mPendingBackups.size());
4350             for (BackupRequest req : mPendingBackups.values()) {
4351                 pw.println("    " + req);
4352             }
4353 
4354             pw.println(userPrefix + "Full backup queue:" + mFullBackupQueue.size());
4355             for (FullBackupEntry entry : mFullBackupQueue) {
4356                 pw.print("    ");
4357                 pw.print(entry.lastBackup);
4358                 pw.print(" : ");
4359                 pw.println(entry.packageName);
4360             }
4361         }
4362     }
4363 
4364     @VisibleForTesting
getOperationTypeFromTransport(TransportClient transportClient)4365     @OperationType int getOperationTypeFromTransport(TransportClient transportClient)
4366             throws TransportNotAvailableException, RemoteException {
4367         if (!shouldUseNewBackupEligibilityRules()) {
4368             // Return the default to stick to the legacy behaviour.
4369             return OperationType.BACKUP;
4370         }
4371 
4372         long oldCallingId = Binder.clearCallingIdentity();
4373         try {
4374             IBackupTransport transport = transportClient.connectOrThrow(
4375                     /* caller */ "BMS.getOperationTypeFromTransport");
4376             if ((transport.getTransportFlags() & BackupAgent.FLAG_DEVICE_TO_DEVICE_TRANSFER) != 0) {
4377                 return OperationType.MIGRATION;
4378             } else {
4379                 return OperationType.BACKUP;
4380             }
4381         } finally {
4382             Binder.restoreCallingIdentity(oldCallingId);
4383         }
4384     }
4385 
4386     @VisibleForTesting
shouldUseNewBackupEligibilityRules()4387     boolean shouldUseNewBackupEligibilityRules() {
4388         return FeatureFlagUtils.isEnabled(mContext,
4389                 FeatureFlagUtils.SETTINGS_USE_NEW_BACKUP_ELIGIBILITY_RULES);
4390     }
4391 
addUserIdToLogMessage(int userId, String message)4392     private static String addUserIdToLogMessage(int userId, String message) {
4393         return "[UserID:" + userId + "] " + message;
4394     }
4395 
4396 
getBackupManagerBinder()4397     public IBackupManager getBackupManagerBinder() {
4398         return mBackupManagerBinder;
4399     }
4400 }
4401