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