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