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