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