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