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