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