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