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