Home | History | Annotate | Download | only in backup
      1 /*
      2  * Copyright (C) 2009 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 android.app.ActivityManagerNative;
     22 import android.app.AlarmManager;
     23 import android.app.AppGlobals;
     24 import android.app.IActivityManager;
     25 import android.app.IApplicationThread;
     26 import android.app.IBackupAgent;
     27 import android.app.PackageInstallObserver;
     28 import android.app.PendingIntent;
     29 import android.app.backup.BackupAgent;
     30 import android.app.backup.BackupDataInput;
     31 import android.app.backup.BackupDataOutput;
     32 import android.app.backup.BackupManager;
     33 import android.app.backup.BackupProgress;
     34 import android.app.backup.BackupTransport;
     35 import android.app.backup.FullBackup;
     36 import android.app.backup.FullBackupDataOutput;
     37 import android.app.backup.IBackupObserver;
     38 import android.app.backup.RestoreDescription;
     39 import android.app.backup.RestoreSet;
     40 import android.app.backup.IBackupManager;
     41 import android.app.backup.IFullBackupRestoreObserver;
     42 import android.app.backup.IRestoreObserver;
     43 import android.app.backup.IRestoreSession;
     44 import android.content.ActivityNotFoundException;
     45 import android.content.BroadcastReceiver;
     46 import android.content.ComponentName;
     47 import android.content.ContentResolver;
     48 import android.content.Context;
     49 import android.content.Intent;
     50 import android.content.IntentFilter;
     51 import android.content.ServiceConnection;
     52 import android.content.pm.ApplicationInfo;
     53 import android.content.pm.IPackageDataObserver;
     54 import android.content.pm.IPackageDeleteObserver;
     55 import android.content.pm.IPackageManager;
     56 import android.content.pm.PackageInfo;
     57 import android.content.pm.PackageManager;
     58 import android.content.pm.ResolveInfo;
     59 import android.content.pm.ServiceInfo;
     60 import android.content.pm.Signature;
     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.Build;
     66 import android.os.Bundle;
     67 import android.os.Environment;
     68 import android.os.Handler;
     69 import android.os.HandlerThread;
     70 import android.os.IBinder;
     71 import android.os.Looper;
     72 import android.os.Message;
     73 import android.os.ParcelFileDescriptor;
     74 import android.os.PowerManager;
     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.UserHandle;
     81 import android.os.WorkSource;
     82 import android.os.Environment.UserEnvironment;
     83 import android.os.storage.IMountService;
     84 import android.os.storage.StorageManager;
     85 import android.provider.Settings;
     86 import android.system.ErrnoException;
     87 import android.system.Os;
     88 import android.text.TextUtils;
     89 import android.util.ArrayMap;
     90 import android.util.ArraySet;
     91 import android.util.AtomicFile;
     92 import android.util.EventLog;
     93 import android.util.Log;
     94 import android.util.Pair;
     95 import android.util.Slog;
     96 import android.util.SparseArray;
     97 import android.util.StringBuilderPrinter;
     98 
     99 import com.android.internal.annotations.GuardedBy;
    100 import com.android.internal.backup.IBackupTransport;
    101 import com.android.internal.backup.IObbBackupService;
    102 import com.android.server.AppWidgetBackupBridge;
    103 import com.android.server.EventLogTags;
    104 import com.android.server.SystemConfig;
    105 import com.android.server.SystemService;
    106 import com.android.server.backup.PackageManagerBackupAgent.Metadata;
    107 
    108 import java.io.BufferedInputStream;
    109 import java.io.BufferedOutputStream;
    110 import java.io.ByteArrayInputStream;
    111 import java.io.ByteArrayOutputStream;
    112 import java.io.DataInputStream;
    113 import java.io.DataOutputStream;
    114 import java.io.EOFException;
    115 import java.io.File;
    116 import java.io.FileDescriptor;
    117 import java.io.FileInputStream;
    118 import java.io.FileNotFoundException;
    119 import java.io.FileOutputStream;
    120 import java.io.IOException;
    121 import java.io.InputStream;
    122 import java.io.OutputStream;
    123 import java.io.PrintWriter;
    124 import java.io.RandomAccessFile;
    125 import java.security.InvalidAlgorithmParameterException;
    126 import java.security.InvalidKeyException;
    127 import java.security.Key;
    128 import java.security.MessageDigest;
    129 import java.security.NoSuchAlgorithmException;
    130 import java.security.SecureRandom;
    131 import java.security.spec.InvalidKeySpecException;
    132 import java.security.spec.KeySpec;
    133 import java.text.SimpleDateFormat;
    134 import java.util.ArrayList;
    135 import java.util.Arrays;
    136 import java.util.Collections;
    137 import java.util.Date;
    138 import java.util.HashMap;
    139 import java.util.HashSet;
    140 import java.util.Iterator;
    141 import java.util.List;
    142 import java.util.Map;
    143 import java.util.Map.Entry;
    144 import java.util.Objects;
    145 import java.util.Random;
    146 import java.util.Set;
    147 import java.util.TreeMap;
    148 import java.util.concurrent.CountDownLatch;
    149 import java.util.concurrent.TimeUnit;
    150 import java.util.concurrent.atomic.AtomicBoolean;
    151 import java.util.concurrent.atomic.AtomicInteger;
    152 import java.util.concurrent.atomic.AtomicLong;
    153 import java.util.zip.Deflater;
    154 import java.util.zip.DeflaterOutputStream;
    155 import java.util.zip.InflaterInputStream;
    156 
    157 import javax.crypto.BadPaddingException;
    158 import javax.crypto.Cipher;
    159 import javax.crypto.CipherInputStream;
    160 import javax.crypto.CipherOutputStream;
    161 import javax.crypto.IllegalBlockSizeException;
    162 import javax.crypto.NoSuchPaddingException;
    163 import javax.crypto.SecretKey;
    164 import javax.crypto.SecretKeyFactory;
    165 import javax.crypto.spec.IvParameterSpec;
    166 import javax.crypto.spec.PBEKeySpec;
    167 import javax.crypto.spec.SecretKeySpec;
    168 
    169 import libcore.io.IoUtils;
    170 
    171 public class BackupManagerService {
    172 
    173     private static final String TAG = "BackupManagerService";
    174     static final boolean DEBUG = true;
    175     static final boolean MORE_DEBUG = false;
    176     static final boolean DEBUG_SCHEDULING = MORE_DEBUG || true;
    177 
    178     // File containing backup-enabled state.  Contains a single byte;
    179     // nonzero == enabled.  File missing or contains a zero byte == disabled.
    180     static final String BACKUP_ENABLE_FILE = "backup_enabled";
    181 
    182     // System-private key used for backing up an app's widget state.  Must
    183     // begin with U+FFxx by convention (we reserve all keys starting
    184     // with U+FF00 or higher for system use).
    185     static final String KEY_WIDGET_STATE = "\uffed\uffedwidget";
    186 
    187     // Historical and current algorithm names
    188     static final String PBKDF_CURRENT = "PBKDF2WithHmacSHA1";
    189     static final String PBKDF_FALLBACK = "PBKDF2WithHmacSHA1And8bit";
    190 
    191     // Name and current contents version of the full-backup manifest file
    192     //
    193     // Manifest version history:
    194     //
    195     // 1 : initial release
    196     static final String BACKUP_MANIFEST_FILENAME = "_manifest";
    197     static final int BACKUP_MANIFEST_VERSION = 1;
    198 
    199     // External archive format version history:
    200     //
    201     // 1 : initial release
    202     // 2 : no format change per se; version bump to facilitate PBKDF2 version skew detection
    203     // 3 : introduced "_meta" metadata file; no other format change per se
    204     // 4 : added support for new device-encrypted storage locations
    205     static final int BACKUP_FILE_VERSION = 4;
    206     static final String BACKUP_FILE_HEADER_MAGIC = "ANDROID BACKUP\n";
    207     static final int BACKUP_PW_FILE_VERSION = 2;
    208     static final String BACKUP_METADATA_FILENAME = "_meta";
    209     static final int BACKUP_METADATA_VERSION = 1;
    210     static final int BACKUP_WIDGET_METADATA_TOKEN = 0x01FFED01;
    211     static final boolean COMPRESS_FULL_BACKUPS = true; // should be true in production
    212 
    213     static final String SETTINGS_PACKAGE = "com.android.providers.settings";
    214     static final String SHARED_BACKUP_AGENT_PACKAGE = "com.android.sharedstoragebackup";
    215     static final String SERVICE_ACTION_TRANSPORT_HOST = "android.backup.TRANSPORT_HOST";
    216 
    217     // Retry interval for clear/init when the transport is unavailable
    218     private static final long TRANSPORT_RETRY_INTERVAL = 1 * AlarmManager.INTERVAL_HOUR;
    219 
    220     private static final String RUN_BACKUP_ACTION = "android.app.backup.intent.RUN";
    221     private static final String RUN_INITIALIZE_ACTION = "android.app.backup.intent.INIT";
    222     private static final int MSG_RUN_BACKUP = 1;
    223     private static final int MSG_RUN_ADB_BACKUP = 2;
    224     private static final int MSG_RUN_RESTORE = 3;
    225     private static final int MSG_RUN_CLEAR = 4;
    226     private static final int MSG_RUN_INITIALIZE = 5;
    227     private static final int MSG_RUN_GET_RESTORE_SETS = 6;
    228     private static final int MSG_TIMEOUT = 7;
    229     private static final int MSG_RESTORE_TIMEOUT = 8;
    230     private static final int MSG_FULL_CONFIRMATION_TIMEOUT = 9;
    231     private static final int MSG_RUN_ADB_RESTORE = 10;
    232     private static final int MSG_RETRY_INIT = 11;
    233     private static final int MSG_RETRY_CLEAR = 12;
    234     private static final int MSG_WIDGET_BROADCAST = 13;
    235     private static final int MSG_RUN_FULL_TRANSPORT_BACKUP = 14;
    236     private static final int MSG_REQUEST_BACKUP = 15;
    237     private static final int MSG_SCHEDULE_BACKUP_PACKAGE = 16;
    238 
    239     // backup task state machine tick
    240     static final int MSG_BACKUP_RESTORE_STEP = 20;
    241     static final int MSG_OP_COMPLETE = 21;
    242 
    243     // Timeout interval for deciding that a bind or clear-data has taken too long
    244     static final long TIMEOUT_INTERVAL = 10 * 1000;
    245 
    246     // Timeout intervals for agent backup & restore operations
    247     static final long TIMEOUT_BACKUP_INTERVAL = 30 * 1000;
    248     static final long TIMEOUT_FULL_BACKUP_INTERVAL = 5 * 60 * 1000;
    249     static final long TIMEOUT_SHARED_BACKUP_INTERVAL = 30 * 60 * 1000;
    250     static final long TIMEOUT_RESTORE_INTERVAL = 60 * 1000;
    251     static final long TIMEOUT_RESTORE_FINISHED_INTERVAL = 30 * 1000;
    252 
    253     // User confirmation timeout for a full backup/restore operation.  It's this long in
    254     // order to give them time to enter the backup password.
    255     static final long TIMEOUT_FULL_CONFIRMATION = 60 * 1000;
    256 
    257     // How long between attempts to perform a full-data backup of any given app
    258     static final long MIN_FULL_BACKUP_INTERVAL = 1000 * 60 * 60 * 24; // one day
    259 
    260     // If an app is busy when we want to do a full-data backup, how long to defer the retry.
    261     // This is fuzzed, so there are two parameters; backoff_min + Rand[0, backoff_fuzz)
    262     static final long BUSY_BACKOFF_MIN_MILLIS = 1000 * 60 * 60;  // one hour
    263     static final int BUSY_BACKOFF_FUZZ = 1000 * 60 * 60 * 2;  // two hours
    264 
    265     Context mContext;
    266     private PackageManager mPackageManager;
    267     IPackageManager mPackageManagerBinder;
    268     private IActivityManager mActivityManager;
    269     private PowerManager mPowerManager;
    270     private AlarmManager mAlarmManager;
    271     private IMountService mMountService;
    272     IBackupManager mBackupManagerBinder;
    273 
    274     boolean mEnabled;   // access to this is synchronized on 'this'
    275     boolean mProvisioned;
    276     boolean mAutoRestore;
    277     PowerManager.WakeLock mWakelock;
    278     HandlerThread mHandlerThread;
    279     BackupHandler mBackupHandler;
    280     PendingIntent mRunBackupIntent, mRunInitIntent;
    281     BroadcastReceiver mRunBackupReceiver, mRunInitReceiver;
    282     // map UIDs to the set of participating packages under that UID
    283     final SparseArray<HashSet<String>> mBackupParticipants
    284             = new SparseArray<HashSet<String>>();
    285     // set of backup services that have pending changes
    286     class BackupRequest {
    287         public String packageName;
    288 
    289         BackupRequest(String pkgName) {
    290             packageName = pkgName;
    291         }
    292 
    293         public String toString() {
    294             return "BackupRequest{pkg=" + packageName + "}";
    295         }
    296     }
    297     // Backups that we haven't started yet.  Keys are package names.
    298     HashMap<String,BackupRequest> mPendingBackups
    299             = new HashMap<String,BackupRequest>();
    300 
    301     // Pseudoname that we use for the Package Manager metadata "package"
    302     static final String PACKAGE_MANAGER_SENTINEL = "@pm@";
    303 
    304     // locking around the pending-backup management
    305     final Object mQueueLock = new Object();
    306 
    307     // The thread performing the sequence of queued backups binds to each app's agent
    308     // in succession.  Bind notifications are asynchronously delivered through the
    309     // Activity Manager; use this lock object to signal when a requested binding has
    310     // completed.
    311     final Object mAgentConnectLock = new Object();
    312     IBackupAgent mConnectedAgent;
    313     volatile boolean mBackupRunning;
    314     volatile boolean mConnecting;
    315     volatile long mLastBackupPass;
    316 
    317     // For debugging, we maintain a progress trace of operations during backup
    318     static final boolean DEBUG_BACKUP_TRACE = true;
    319     final List<String> mBackupTrace = new ArrayList<String>();
    320 
    321     // A similar synchronization mechanism around clearing apps' data for restore
    322     final Object mClearDataLock = new Object();
    323     volatile boolean mClearingData;
    324 
    325     // Transport bookkeeping
    326     final ArraySet<ComponentName> mTransportWhitelist;
    327     final Intent mTransportServiceIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST);
    328     final ArrayMap<String,String> mTransportNames
    329             = new ArrayMap<String,String>();             // component name -> registration name
    330     final ArrayMap<String,IBackupTransport> mTransports
    331             = new ArrayMap<String,IBackupTransport>();   // registration name -> binder
    332     final ArrayMap<String,TransportConnection> mTransportConnections
    333             = new ArrayMap<String,TransportConnection>();
    334     String mCurrentTransport;
    335     ActiveRestoreSession mActiveRestoreSession;
    336 
    337     // Watch the device provisioning operation during setup
    338     ContentObserver mProvisionedObserver;
    339 
    340     // The published binder is actually to a singleton trampoline object that calls
    341     // through to the proper code.  This indirection lets us turn down the heavy
    342     // implementation object on the fly without disturbing binders that have been
    343     // cached elsewhere in the system.
    344     static Trampoline sInstance;
    345     static Trampoline getInstance() {
    346         // Always constructed during system bringup, so no need to lazy-init
    347         return sInstance;
    348     }
    349 
    350     public static final class Lifecycle extends SystemService {
    351 
    352         public Lifecycle(Context context) {
    353             super(context);
    354             sInstance = new Trampoline(context);
    355         }
    356 
    357         @Override
    358         public void onStart() {
    359             publishBinderService(Context.BACKUP_SERVICE, sInstance);
    360         }
    361 
    362         @Override
    363         public void onUnlockUser(int userId) {
    364             if (userId == UserHandle.USER_SYSTEM) {
    365                 sInstance.initialize(userId);
    366 
    367                 // Migrate legacy setting
    368                 if (!backupSettingMigrated(userId)) {
    369                     if (DEBUG) {
    370                         Slog.i(TAG, "Backup enable apparently not migrated");
    371                     }
    372                     final ContentResolver r = sInstance.mContext.getContentResolver();
    373                     final int enableState = Settings.Secure.getIntForUser(r,
    374                             Settings.Secure.BACKUP_ENABLED, -1, userId);
    375                     if (enableState >= 0) {
    376                         if (DEBUG) {
    377                             Slog.i(TAG, "Migrating enable state " + (enableState != 0));
    378                         }
    379                         writeBackupEnableState(enableState != 0, userId);
    380                         Settings.Secure.putStringForUser(r,
    381                                 Settings.Secure.BACKUP_ENABLED, null, userId);
    382                     } else {
    383                         if (DEBUG) {
    384                             Slog.i(TAG, "Backup not yet configured; retaining null enable state");
    385                         }
    386                     }
    387                 }
    388 
    389                 try {
    390                     sInstance.setBackupEnabled(readBackupEnableState(userId));
    391                 } catch (RemoteException e) {
    392                     // can't happen; it's a local object
    393                 }
    394             }
    395         }
    396     }
    397 
    398     class ProvisionedObserver extends ContentObserver {
    399         public ProvisionedObserver(Handler handler) {
    400             super(handler);
    401         }
    402 
    403         public void onChange(boolean selfChange) {
    404             final boolean wasProvisioned = mProvisioned;
    405             final boolean isProvisioned = deviceIsProvisioned();
    406             // latch: never unprovision
    407             mProvisioned = wasProvisioned || isProvisioned;
    408             if (MORE_DEBUG) {
    409                 Slog.d(TAG, "Provisioning change: was=" + wasProvisioned
    410                         + " is=" + isProvisioned + " now=" + mProvisioned);
    411             }
    412 
    413             synchronized (mQueueLock) {
    414                 if (mProvisioned && !wasProvisioned && mEnabled) {
    415                     // we're now good to go, so start the backup alarms
    416                     if (MORE_DEBUG) Slog.d(TAG, "Now provisioned, so starting backups");
    417                     KeyValueBackupJob.schedule(mContext);
    418                     scheduleNextFullBackupJob(0);
    419                 }
    420             }
    421         }
    422     }
    423 
    424     class RestoreGetSetsParams {
    425         public IBackupTransport transport;
    426         public ActiveRestoreSession session;
    427         public IRestoreObserver observer;
    428 
    429         RestoreGetSetsParams(IBackupTransport _transport, ActiveRestoreSession _session,
    430                 IRestoreObserver _observer) {
    431             transport = _transport;
    432             session = _session;
    433             observer = _observer;
    434         }
    435     }
    436 
    437     class RestoreParams {
    438         public IBackupTransport transport;
    439         public String dirName;
    440         public IRestoreObserver observer;
    441         public long token;
    442         public PackageInfo pkgInfo;
    443         public int pmToken; // in post-install restore, the PM's token for this transaction
    444         public boolean isSystemRestore;
    445         public String[] filterSet;
    446 
    447         /**
    448          * Restore a single package; no kill after restore
    449          */
    450         RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
    451                 long _token, PackageInfo _pkg) {
    452             transport = _transport;
    453             dirName = _dirName;
    454             observer = _obs;
    455             token = _token;
    456             pkgInfo = _pkg;
    457             pmToken = 0;
    458             isSystemRestore = false;
    459             filterSet = null;
    460         }
    461 
    462         /**
    463          * Restore at install: PM token needed, kill after restore
    464          */
    465         RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
    466                 long _token, String _pkgName, int _pmToken) {
    467             transport = _transport;
    468             dirName = _dirName;
    469             observer = _obs;
    470             token = _token;
    471             pkgInfo = null;
    472             pmToken = _pmToken;
    473             isSystemRestore = false;
    474             filterSet = new String[] { _pkgName };
    475         }
    476 
    477         /**
    478          * Restore everything possible.  This is the form that Setup Wizard or similar
    479          * restore UXes use.
    480          */
    481         RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
    482                 long _token) {
    483             transport = _transport;
    484             dirName = _dirName;
    485             observer = _obs;
    486             token = _token;
    487             pkgInfo = null;
    488             pmToken = 0;
    489             isSystemRestore = true;
    490             filterSet = null;
    491         }
    492 
    493         /**
    494          * Restore some set of packages.  Leave this one up to the caller to specify
    495          * whether it's to be considered a system-level restore.
    496          */
    497         RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
    498                 long _token, String[] _filterSet, boolean _isSystemRestore) {
    499             transport = _transport;
    500             dirName = _dirName;
    501             observer = _obs;
    502             token = _token;
    503             pkgInfo = null;
    504             pmToken = 0;
    505             isSystemRestore = _isSystemRestore;
    506             filterSet = _filterSet;
    507         }
    508     }
    509 
    510     class ClearParams {
    511         public IBackupTransport transport;
    512         public PackageInfo packageInfo;
    513 
    514         ClearParams(IBackupTransport _transport, PackageInfo _info) {
    515             transport = _transport;
    516             packageInfo = _info;
    517         }
    518     }
    519 
    520     class ClearRetryParams {
    521         public String transportName;
    522         public String packageName;
    523 
    524         ClearRetryParams(String transport, String pkg) {
    525             transportName = transport;
    526             packageName = pkg;
    527         }
    528     }
    529 
    530     class FullParams {
    531         public ParcelFileDescriptor fd;
    532         public final AtomicBoolean latch;
    533         public IFullBackupRestoreObserver observer;
    534         public String curPassword;     // filled in by the confirmation step
    535         public String encryptPassword;
    536 
    537         FullParams() {
    538             latch = new AtomicBoolean(false);
    539         }
    540     }
    541 
    542     class FullBackupParams extends FullParams {
    543         public boolean includeApks;
    544         public boolean includeObbs;
    545         public boolean includeShared;
    546         public boolean doWidgets;
    547         public boolean allApps;
    548         public boolean includeSystem;
    549         public boolean doCompress;
    550         public String[] packages;
    551 
    552         FullBackupParams(ParcelFileDescriptor output, boolean saveApks, boolean saveObbs,
    553                 boolean saveShared, boolean alsoWidgets, boolean doAllApps, boolean doSystem,
    554                 boolean compress, String[] pkgList) {
    555             fd = output;
    556             includeApks = saveApks;
    557             includeObbs = saveObbs;
    558             includeShared = saveShared;
    559             doWidgets = alsoWidgets;
    560             allApps = doAllApps;
    561             includeSystem = doSystem;
    562             doCompress = compress;
    563             packages = pkgList;
    564         }
    565     }
    566 
    567     class FullRestoreParams extends FullParams {
    568         FullRestoreParams(ParcelFileDescriptor input) {
    569             fd = input;
    570         }
    571     }
    572 
    573     class BackupParams {
    574         public IBackupTransport transport;
    575         public String dirName;
    576         public ArrayList<String> kvPackages;
    577         public ArrayList<String> fullPackages;
    578         public IBackupObserver observer;
    579         public boolean userInitiated;
    580 
    581         BackupParams(IBackupTransport transport, String dirName, ArrayList<String> kvPackages,
    582                 ArrayList<String> fullPackages, IBackupObserver observer, boolean userInitiated) {
    583             this.transport = transport;
    584             this.dirName = dirName;
    585             this.kvPackages = kvPackages;
    586             this.fullPackages = fullPackages;
    587             this.observer = observer;
    588             this.userInitiated = userInitiated;
    589         }
    590     }
    591 
    592     // Bookkeeping of in-flight operations for timeout etc. purposes.  The operation
    593     // token is the index of the entry in the pending-operations list.
    594     static final int OP_PENDING = 0;
    595     static final int OP_ACKNOWLEDGED = 1;
    596     static final int OP_TIMEOUT = -1;
    597 
    598     class Operation {
    599         public int state;
    600         public BackupRestoreTask callback;
    601 
    602         Operation(int initialState, BackupRestoreTask callbackObj) {
    603             state = initialState;
    604             callback = callbackObj;
    605         }
    606     }
    607     final SparseArray<Operation> mCurrentOperations = new SparseArray<Operation>();
    608     final Object mCurrentOpLock = new Object();
    609     final Random mTokenGenerator = new Random();
    610 
    611     final SparseArray<FullParams> mFullConfirmations = new SparseArray<FullParams>();
    612 
    613     // Where we keep our journal files and other bookkeeping
    614     File mBaseStateDir;
    615     File mDataDir;
    616     File mJournalDir;
    617     File mJournal;
    618 
    619     // Backup password, if any, and the file where it's saved.  What is stored is not the
    620     // password text itself; it's the result of a PBKDF2 hash with a randomly chosen (but
    621     // persisted) salt.  Validation is performed by running the challenge text through the
    622     // same PBKDF2 cycle with the persisted salt; if the resulting derived key string matches
    623     // the saved hash string, then the challenge text matches the originally supplied
    624     // password text.
    625     private final SecureRandom mRng = new SecureRandom();
    626     private String mPasswordHash;
    627     private File mPasswordHashFile;
    628     private int mPasswordVersion;
    629     private File mPasswordVersionFile;
    630     private byte[] mPasswordSalt;
    631 
    632     // Configuration of PBKDF2 that we use for generating pw hashes and intermediate keys
    633     static final int PBKDF2_HASH_ROUNDS = 10000;
    634     static final int PBKDF2_KEY_SIZE = 256;     // bits
    635     static final int PBKDF2_SALT_SIZE = 512;    // bits
    636     static final String ENCRYPTION_ALGORITHM_NAME = "AES-256";
    637 
    638     // Keep a log of all the apps we've ever backed up, and what the
    639     // dataset tokens are for both the current backup dataset and
    640     // the ancestral dataset.
    641     private File mEverStored;
    642     HashSet<String> mEverStoredApps = new HashSet<String>();
    643 
    644     static final int CURRENT_ANCESTRAL_RECORD_VERSION = 1;  // increment when the schema changes
    645     File mTokenFile;
    646     Set<String> mAncestralPackages = null;
    647     long mAncestralToken = 0;
    648     long mCurrentToken = 0;
    649 
    650     // Persistently track the need to do a full init
    651     static final String INIT_SENTINEL_FILE_NAME = "_need_init_";
    652     HashSet<String> mPendingInits = new HashSet<String>();  // transport names
    653 
    654     // Round-robin queue for scheduling full backup passes
    655     static final int SCHEDULE_FILE_VERSION = 1; // current version of the schedule file
    656     class FullBackupEntry implements Comparable<FullBackupEntry> {
    657         String packageName;
    658         long lastBackup;
    659 
    660         FullBackupEntry(String pkg, long when) {
    661             packageName = pkg;
    662             lastBackup = when;
    663         }
    664 
    665         @Override
    666         public int compareTo(FullBackupEntry other) {
    667             if (lastBackup < other.lastBackup) return -1;
    668             else if (lastBackup > other.lastBackup) return 1;
    669             else return 0;
    670         }
    671     }
    672 
    673     File mFullBackupScheduleFile;
    674     // If we're running a schedule-driven full backup, this is the task instance doing it
    675 
    676     @GuardedBy("mQueueLock")
    677     PerformFullTransportBackupTask mRunningFullBackupTask;
    678 
    679     @GuardedBy("mQueueLock")
    680     ArrayList<FullBackupEntry> mFullBackupQueue;
    681 
    682     // Utility: build a new random integer token
    683     int generateToken() {
    684         int token;
    685         do {
    686             synchronized (mTokenGenerator) {
    687                 token = mTokenGenerator.nextInt();
    688             }
    689         } while (token < 0);
    690         return token;
    691     }
    692 
    693     // High level policy: apps are generally ineligible for backup if certain conditions apply
    694     public static boolean appIsEligibleForBackup(ApplicationInfo app) {
    695         // 1. their manifest states android:allowBackup="false"
    696         if ((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) {
    697             return false;
    698         }
    699 
    700         // 2. they run as a system-level uid but do not supply their own backup agent
    701         if ((app.uid < Process.FIRST_APPLICATION_UID) && (app.backupAgentName == null)) {
    702             return false;
    703         }
    704 
    705         // 3. it is the special shared-storage backup package used for 'adb backup'
    706         if (app.packageName.equals(BackupManagerService.SHARED_BACKUP_AGENT_PACKAGE)) {
    707             return false;
    708         }
    709 
    710         return true;
    711     }
    712 
    713     // Checks if the app is in a stopped state, that means it won't receive broadcasts.
    714     private static boolean appIsStopped(ApplicationInfo app) {
    715         return ((app.flags & ApplicationInfo.FLAG_STOPPED) != 0);
    716     }
    717 
    718     /* does *not* check overall backup eligibility policy! */
    719     private static boolean appGetsFullBackup(PackageInfo pkg) {
    720         if (pkg.applicationInfo.backupAgentName != null) {
    721             // If it has an agent, it gets full backups only if it says so
    722             return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_FULL_BACKUP_ONLY) != 0;
    723         }
    724 
    725         // No agent or fullBackupOnly="true" means we do indeed perform full-data backups for it
    726         return true;
    727     }
    728 
    729     /* adb backup: is this app only capable of doing key/value?  We say otherwise if
    730      * the app has a backup agent and does not say fullBackupOnly, *unless* it
    731      * is a package that we know _a priori_ explicitly supports both key/value and
    732      * full-data backup.
    733      */
    734     private static boolean appIsKeyValueOnly(PackageInfo pkg) {
    735         if ("com.android.providers.settings".equals(pkg.packageName)) {
    736             return false;
    737         }
    738 
    739         return !appGetsFullBackup(pkg);
    740     }
    741 
    742     // ----- Asynchronous backup/restore handler thread -----
    743 
    744     private class BackupHandler extends Handler {
    745         public BackupHandler(Looper looper) {
    746             super(looper);
    747         }
    748 
    749         public void handleMessage(Message msg) {
    750 
    751             switch (msg.what) {
    752             case MSG_RUN_BACKUP:
    753             {
    754                 mLastBackupPass = System.currentTimeMillis();
    755 
    756                 IBackupTransport transport = getTransport(mCurrentTransport);
    757                 if (transport == null) {
    758                     Slog.v(TAG, "Backup requested but no transport available");
    759                     synchronized (mQueueLock) {
    760                         mBackupRunning = false;
    761                     }
    762                     mWakelock.release();
    763                     break;
    764                 }
    765 
    766                 // snapshot the pending-backup set and work on that
    767                 ArrayList<BackupRequest> queue = new ArrayList<BackupRequest>();
    768                 File oldJournal = mJournal;
    769                 synchronized (mQueueLock) {
    770                     // Do we have any work to do?  Construct the work queue
    771                     // then release the synchronization lock to actually run
    772                     // the backup.
    773                     if (mPendingBackups.size() > 0) {
    774                         for (BackupRequest b: mPendingBackups.values()) {
    775                             queue.add(b);
    776                         }
    777                         if (DEBUG) Slog.v(TAG, "clearing pending backups");
    778                         mPendingBackups.clear();
    779 
    780                         // Start a new backup-queue journal file too
    781                         mJournal = null;
    782 
    783                     }
    784                 }
    785 
    786                 // At this point, we have started a new journal file, and the old
    787                 // file identity is being passed to the backup processing task.
    788                 // When it completes successfully, that old journal file will be
    789                 // deleted.  If we crash prior to that, the old journal is parsed
    790                 // at next boot and the journaled requests fulfilled.
    791                 boolean staged = true;
    792                 if (queue.size() > 0) {
    793                     // Spin up a backup state sequence and set it running
    794                     try {
    795                         String dirName = transport.transportDirName();
    796                         PerformBackupTask pbt = new PerformBackupTask(transport, dirName,
    797                                 queue, oldJournal, null, null, false);
    798                         Message pbtMessage = obtainMessage(MSG_BACKUP_RESTORE_STEP, pbt);
    799                         sendMessage(pbtMessage);
    800                     } catch (Exception e) {
    801                         // unable to ask the transport its dir name -- transient failure, since
    802                         // the above check succeeded.  Try again next time.
    803                         Slog.e(TAG, "Transport became unavailable attempting backup");
    804                         staged = false;
    805                     }
    806                 } else {
    807                     Slog.v(TAG, "Backup requested but nothing pending");
    808                     staged = false;
    809                 }
    810 
    811                 if (!staged) {
    812                     // if we didn't actually hand off the wakelock, rewind until next time
    813                     synchronized (mQueueLock) {
    814                         mBackupRunning = false;
    815                     }
    816                     mWakelock.release();
    817                 }
    818                 break;
    819             }
    820 
    821             case MSG_BACKUP_RESTORE_STEP:
    822             {
    823                 try {
    824                     BackupRestoreTask task = (BackupRestoreTask) msg.obj;
    825                     if (MORE_DEBUG) Slog.v(TAG, "Got next step for " + task + ", executing");
    826                     task.execute();
    827                 } catch (ClassCastException e) {
    828                     Slog.e(TAG, "Invalid backup task in flight, obj=" + msg.obj);
    829                 }
    830                 break;
    831             }
    832 
    833             case MSG_OP_COMPLETE:
    834             {
    835                 try {
    836                     Pair<BackupRestoreTask, Long> taskWithResult =
    837                             (Pair<BackupRestoreTask, Long>) msg.obj;
    838                     taskWithResult.first.operationComplete(taskWithResult.second);
    839                 } catch (ClassCastException e) {
    840                     Slog.e(TAG, "Invalid completion in flight, obj=" + msg.obj);
    841                 }
    842                 break;
    843             }
    844 
    845             case MSG_RUN_ADB_BACKUP:
    846             {
    847                 // TODO: refactor full backup to be a looper-based state machine
    848                 // similar to normal backup/restore.
    849                 FullBackupParams params = (FullBackupParams)msg.obj;
    850                 PerformAdbBackupTask task = new PerformAdbBackupTask(params.fd,
    851                         params.observer, params.includeApks, params.includeObbs,
    852                         params.includeShared, params.doWidgets,
    853                         params.curPassword, params.encryptPassword,
    854                         params.allApps, params.includeSystem, params.doCompress,
    855                         params.packages, params.latch);
    856                 (new Thread(task, "adb-backup")).start();
    857                 break;
    858             }
    859 
    860             case MSG_RUN_FULL_TRANSPORT_BACKUP:
    861             {
    862                 PerformFullTransportBackupTask task = (PerformFullTransportBackupTask) msg.obj;
    863                 (new Thread(task, "transport-backup")).start();
    864                 break;
    865             }
    866 
    867             case MSG_RUN_RESTORE:
    868             {
    869                 RestoreParams params = (RestoreParams)msg.obj;
    870                 Slog.d(TAG, "MSG_RUN_RESTORE observer=" + params.observer);
    871                 BackupRestoreTask task = new PerformUnifiedRestoreTask(params.transport,
    872                         params.observer, params.token, params.pkgInfo, params.pmToken,
    873                         params.isSystemRestore, params.filterSet);
    874                 Message restoreMsg = obtainMessage(MSG_BACKUP_RESTORE_STEP, task);
    875                 sendMessage(restoreMsg);
    876                 break;
    877             }
    878 
    879             case MSG_RUN_ADB_RESTORE:
    880             {
    881                 // TODO: refactor full restore to be a looper-based state machine
    882                 // similar to normal backup/restore.
    883                 FullRestoreParams params = (FullRestoreParams)msg.obj;
    884                 PerformAdbRestoreTask task = new PerformAdbRestoreTask(params.fd,
    885                         params.curPassword, params.encryptPassword,
    886                         params.observer, params.latch);
    887                 (new Thread(task, "adb-restore")).start();
    888                 break;
    889             }
    890 
    891             case MSG_RUN_CLEAR:
    892             {
    893                 ClearParams params = (ClearParams)msg.obj;
    894                 (new PerformClearTask(params.transport, params.packageInfo)).run();
    895                 break;
    896             }
    897 
    898             case MSG_RETRY_CLEAR:
    899             {
    900                 // reenqueues if the transport remains unavailable
    901                 ClearRetryParams params = (ClearRetryParams)msg.obj;
    902                 clearBackupData(params.transportName, params.packageName);
    903                 break;
    904             }
    905 
    906             case MSG_RUN_INITIALIZE:
    907             {
    908                 HashSet<String> queue;
    909 
    910                 // Snapshot the pending-init queue and work on that
    911                 synchronized (mQueueLock) {
    912                     queue = new HashSet<String>(mPendingInits);
    913                     mPendingInits.clear();
    914                 }
    915 
    916                 (new PerformInitializeTask(queue)).run();
    917                 break;
    918             }
    919 
    920             case MSG_RETRY_INIT:
    921             {
    922                 synchronized (mQueueLock) {
    923                     recordInitPendingLocked(msg.arg1 != 0, (String)msg.obj);
    924                     mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
    925                             mRunInitIntent);
    926                 }
    927                 break;
    928             }
    929 
    930             case MSG_RUN_GET_RESTORE_SETS:
    931             {
    932                 // Like other async operations, this is entered with the wakelock held
    933                 RestoreSet[] sets = null;
    934                 RestoreGetSetsParams params = (RestoreGetSetsParams)msg.obj;
    935                 try {
    936                     sets = params.transport.getAvailableRestoreSets();
    937                     // cache the result in the active session
    938                     synchronized (params.session) {
    939                         params.session.mRestoreSets = sets;
    940                     }
    941                     if (sets == null) EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
    942                 } catch (Exception e) {
    943                     Slog.e(TAG, "Error from transport getting set list: " + e.getMessage());
    944                 } finally {
    945                     if (params.observer != null) {
    946                         try {
    947                             params.observer.restoreSetsAvailable(sets);
    948                         } catch (RemoteException re) {
    949                             Slog.e(TAG, "Unable to report listing to observer");
    950                         } catch (Exception e) {
    951                             Slog.e(TAG, "Restore observer threw: " + e.getMessage());
    952                         }
    953                     }
    954 
    955                     // Done: reset the session timeout clock
    956                     removeMessages(MSG_RESTORE_TIMEOUT);
    957                     sendEmptyMessageDelayed(MSG_RESTORE_TIMEOUT, TIMEOUT_RESTORE_INTERVAL);
    958 
    959                     mWakelock.release();
    960                 }
    961                 break;
    962             }
    963 
    964             case MSG_TIMEOUT:
    965             {
    966                 handleTimeout(msg.arg1, msg.obj);
    967                 break;
    968             }
    969 
    970             case MSG_RESTORE_TIMEOUT:
    971             {
    972                 synchronized (BackupManagerService.this) {
    973                     if (mActiveRestoreSession != null) {
    974                         // Client app left the restore session dangling.  We know that it
    975                         // can't be in the middle of an actual restore operation because
    976                         // the timeout is suspended while a restore is in progress.  Clean
    977                         // up now.
    978                         Slog.w(TAG, "Restore session timed out; aborting");
    979                         mActiveRestoreSession.markTimedOut();
    980                         post(mActiveRestoreSession.new EndRestoreRunnable(
    981                                 BackupManagerService.this, mActiveRestoreSession));
    982                     }
    983                 }
    984                 break;
    985             }
    986 
    987             case MSG_FULL_CONFIRMATION_TIMEOUT:
    988             {
    989                 synchronized (mFullConfirmations) {
    990                     FullParams params = mFullConfirmations.get(msg.arg1);
    991                     if (params != null) {
    992                         Slog.i(TAG, "Full backup/restore timed out waiting for user confirmation");
    993 
    994                         // Release the waiter; timeout == completion
    995                         signalFullBackupRestoreCompletion(params);
    996 
    997                         // Remove the token from the set
    998                         mFullConfirmations.delete(msg.arg1);
    999 
   1000                         // Report a timeout to the observer, if any
   1001                         if (params.observer != null) {
   1002                             try {
   1003                                 params.observer.onTimeout();
   1004                             } catch (RemoteException e) {
   1005                                 /* don't care if the app has gone away */
   1006                             }
   1007                         }
   1008                     } else {
   1009                         Slog.d(TAG, "couldn't find params for token " + msg.arg1);
   1010                     }
   1011                 }
   1012                 break;
   1013             }
   1014 
   1015             case MSG_WIDGET_BROADCAST:
   1016             {
   1017                 final Intent intent = (Intent) msg.obj;
   1018                 mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
   1019                 break;
   1020             }
   1021 
   1022             case MSG_REQUEST_BACKUP:
   1023             {
   1024                 BackupParams params = (BackupParams)msg.obj;
   1025                 if (MORE_DEBUG) {
   1026                     Slog.d(TAG, "MSG_REQUEST_BACKUP observer=" + params.observer);
   1027                 }
   1028                 ArrayList<BackupRequest> kvQueue = new ArrayList<>();
   1029                 for (String packageName : params.kvPackages) {
   1030                     kvQueue.add(new BackupRequest(packageName));
   1031                 }
   1032                 mBackupRunning = true;
   1033                 mWakelock.acquire();
   1034 
   1035                 PerformBackupTask pbt = new PerformBackupTask(params.transport, params.dirName,
   1036                     kvQueue, null, params.observer, params.fullPackages, true);
   1037                 Message pbtMessage = obtainMessage(MSG_BACKUP_RESTORE_STEP, pbt);
   1038                 sendMessage(pbtMessage);
   1039                 break;
   1040             }
   1041 
   1042             case MSG_SCHEDULE_BACKUP_PACKAGE:
   1043             {
   1044                 String pkgName = (String)msg.obj;
   1045                 if (MORE_DEBUG) {
   1046                     Slog.d(TAG, "MSG_SCHEDULE_BACKUP_PACKAGE " + pkgName);
   1047                 }
   1048                 dataChangedImpl(pkgName);
   1049                 break;
   1050             }
   1051             }
   1052         }
   1053     }
   1054 
   1055     // ----- Debug-only backup operation trace -----
   1056     void addBackupTrace(String s) {
   1057         if (DEBUG_BACKUP_TRACE) {
   1058             synchronized (mBackupTrace) {
   1059                 mBackupTrace.add(s);
   1060             }
   1061         }
   1062     }
   1063 
   1064     void clearBackupTrace() {
   1065         if (DEBUG_BACKUP_TRACE) {
   1066             synchronized (mBackupTrace) {
   1067                 mBackupTrace.clear();
   1068             }
   1069         }
   1070     }
   1071 
   1072     // ----- Main service implementation -----
   1073 
   1074     public BackupManagerService(Context context, Trampoline parent) {
   1075         mContext = context;
   1076         mPackageManager = context.getPackageManager();
   1077         mPackageManagerBinder = AppGlobals.getPackageManager();
   1078         mActivityManager = ActivityManagerNative.getDefault();
   1079 
   1080         mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
   1081         mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
   1082         mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
   1083 
   1084         mBackupManagerBinder = Trampoline.asInterface(parent.asBinder());
   1085 
   1086         // spin up the backup/restore handler thread
   1087         mHandlerThread = new HandlerThread("backup", Process.THREAD_PRIORITY_BACKGROUND);
   1088         mHandlerThread.start();
   1089         mBackupHandler = new BackupHandler(mHandlerThread.getLooper());
   1090 
   1091         // Set up our bookkeeping
   1092         final ContentResolver resolver = context.getContentResolver();
   1093         mProvisioned = Settings.Global.getInt(resolver,
   1094                 Settings.Global.DEVICE_PROVISIONED, 0) != 0;
   1095         mAutoRestore = Settings.Secure.getInt(resolver,
   1096                 Settings.Secure.BACKUP_AUTO_RESTORE, 1) != 0;
   1097 
   1098         mProvisionedObserver = new ProvisionedObserver(mBackupHandler);
   1099         resolver.registerContentObserver(
   1100                 Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED),
   1101                 false, mProvisionedObserver);
   1102 
   1103         // If Encrypted file systems is enabled or disabled, this call will return the
   1104         // correct directory.
   1105         mBaseStateDir = new File(Environment.getDataDirectory(), "backup");
   1106         mBaseStateDir.mkdirs();
   1107         if (!SELinux.restorecon(mBaseStateDir)) {
   1108             Slog.e(TAG, "SELinux restorecon failed on " + mBaseStateDir);
   1109         }
   1110 
   1111         // This dir on /cache is managed directly in init.rc
   1112         mDataDir = new File(Environment.getDownloadCacheDirectory(), "backup_stage");
   1113 
   1114         mPasswordVersion = 1;       // unless we hear otherwise
   1115         mPasswordVersionFile = new File(mBaseStateDir, "pwversion");
   1116         if (mPasswordVersionFile.exists()) {
   1117             FileInputStream fin = null;
   1118             DataInputStream in = null;
   1119             try {
   1120                 fin = new FileInputStream(mPasswordVersionFile);
   1121                 in = new DataInputStream(fin);
   1122                 mPasswordVersion = in.readInt();
   1123             } catch (IOException e) {
   1124                 Slog.e(TAG, "Unable to read backup pw version");
   1125             } finally {
   1126                 try {
   1127                     if (in != null) in.close();
   1128                     if (fin != null) fin.close();
   1129                 } catch (IOException e) {
   1130                     Slog.w(TAG, "Error closing pw version files");
   1131                 }
   1132             }
   1133         }
   1134 
   1135         mPasswordHashFile = new File(mBaseStateDir, "pwhash");
   1136         if (mPasswordHashFile.exists()) {
   1137             FileInputStream fin = null;
   1138             DataInputStream in = null;
   1139             try {
   1140                 fin = new FileInputStream(mPasswordHashFile);
   1141                 in = new DataInputStream(new BufferedInputStream(fin));
   1142                 // integer length of the salt array, followed by the salt,
   1143                 // then the hex pw hash string
   1144                 int saltLen = in.readInt();
   1145                 byte[] salt = new byte[saltLen];
   1146                 in.readFully(salt);
   1147                 mPasswordHash = in.readUTF();
   1148                 mPasswordSalt = salt;
   1149             } catch (IOException e) {
   1150                 Slog.e(TAG, "Unable to read saved backup pw hash");
   1151             } finally {
   1152                 try {
   1153                     if (in != null) in.close();
   1154                     if (fin != null) fin.close();
   1155                 } catch (IOException e) {
   1156                     Slog.w(TAG, "Unable to close streams");
   1157                 }
   1158             }
   1159         }
   1160 
   1161         // Alarm receivers for scheduled backups & initialization operations
   1162         mRunBackupReceiver = new RunBackupReceiver();
   1163         IntentFilter filter = new IntentFilter();
   1164         filter.addAction(RUN_BACKUP_ACTION);
   1165         context.registerReceiver(mRunBackupReceiver, filter,
   1166                 android.Manifest.permission.BACKUP, null);
   1167 
   1168         mRunInitReceiver = new RunInitializeReceiver();
   1169         filter = new IntentFilter();
   1170         filter.addAction(RUN_INITIALIZE_ACTION);
   1171         context.registerReceiver(mRunInitReceiver, filter,
   1172                 android.Manifest.permission.BACKUP, null);
   1173 
   1174         Intent backupIntent = new Intent(RUN_BACKUP_ACTION);
   1175         backupIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
   1176         mRunBackupIntent = PendingIntent.getBroadcast(context, MSG_RUN_BACKUP, backupIntent, 0);
   1177 
   1178         Intent initIntent = new Intent(RUN_INITIALIZE_ACTION);
   1179         backupIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
   1180         mRunInitIntent = PendingIntent.getBroadcast(context, MSG_RUN_INITIALIZE, initIntent, 0);
   1181 
   1182         // Set up the backup-request journaling
   1183         mJournalDir = new File(mBaseStateDir, "pending");
   1184         mJournalDir.mkdirs();   // creates mBaseStateDir along the way
   1185         mJournal = null;        // will be created on first use
   1186 
   1187         // Set up the various sorts of package tracking we do
   1188         mFullBackupScheduleFile = new File(mBaseStateDir, "fb-schedule");
   1189         initPackageTracking();
   1190 
   1191         // Build our mapping of uid to backup client services.  This implicitly
   1192         // schedules a backup pass on the Package Manager metadata the first
   1193         // time anything needs to be backed up.
   1194         synchronized (mBackupParticipants) {
   1195             addPackageParticipantsLocked(null);
   1196         }
   1197 
   1198         // Set up our transport options and initialize the default transport
   1199         // TODO: Don't create transports that we don't need to?
   1200         SystemConfig systemConfig = SystemConfig.getInstance();
   1201         mTransportWhitelist = systemConfig.getBackupTransportWhitelist();
   1202 
   1203         String transport = Settings.Secure.getString(context.getContentResolver(),
   1204                 Settings.Secure.BACKUP_TRANSPORT);
   1205         if (TextUtils.isEmpty(transport)) {
   1206             transport = null;
   1207         }
   1208         mCurrentTransport = transport;
   1209         if (DEBUG) Slog.v(TAG, "Starting with transport " + mCurrentTransport);
   1210 
   1211         // Find all transport hosts and bind to their services
   1212         // TODO: http://b/22388012
   1213         List<ResolveInfo> hosts = mPackageManager.queryIntentServicesAsUser(
   1214                 mTransportServiceIntent, 0, UserHandle.USER_SYSTEM);
   1215         if (DEBUG) {
   1216             Slog.v(TAG, "Found transports: " + ((hosts == null) ? "null" : hosts.size()));
   1217         }
   1218         if (hosts != null) {
   1219             for (int i = 0; i < hosts.size(); i++) {
   1220                 final ServiceInfo transportService = hosts.get(i).serviceInfo;
   1221                 if (MORE_DEBUG) {
   1222                     Slog.v(TAG, "   " + transportService.packageName + "/" + transportService.name);
   1223                 }
   1224                 tryBindTransport(transportService);
   1225             }
   1226         }
   1227 
   1228         // Now that we know about valid backup participants, parse any
   1229         // leftover journal files into the pending backup set
   1230         mBackupHandler.post(() -> parseLeftoverJournals());
   1231 
   1232         // Power management
   1233         mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*");
   1234     }
   1235 
   1236     private class RunBackupReceiver extends BroadcastReceiver {
   1237         public void onReceive(Context context, Intent intent) {
   1238             if (RUN_BACKUP_ACTION.equals(intent.getAction())) {
   1239                 synchronized (mQueueLock) {
   1240                     if (mPendingInits.size() > 0) {
   1241                         // If there are pending init operations, we process those
   1242                         // and then settle into the usual periodic backup schedule.
   1243                         if (MORE_DEBUG) Slog.v(TAG, "Init pending at scheduled backup");
   1244                         try {
   1245                             mAlarmManager.cancel(mRunInitIntent);
   1246                             mRunInitIntent.send();
   1247                         } catch (PendingIntent.CanceledException ce) {
   1248                             Slog.e(TAG, "Run init intent cancelled");
   1249                             // can't really do more than bail here
   1250                         }
   1251                     } else {
   1252                         // Don't run backups now if we're disabled or not yet
   1253                         // fully set up.
   1254                         if (mEnabled && mProvisioned) {
   1255                             if (!mBackupRunning) {
   1256                                 if (DEBUG) Slog.v(TAG, "Running a backup pass");
   1257 
   1258                                 // Acquire the wakelock and pass it to the backup thread.  it will
   1259                                 // be released once backup concludes.
   1260                                 mBackupRunning = true;
   1261                                 mWakelock.acquire();
   1262 
   1263                                 Message msg = mBackupHandler.obtainMessage(MSG_RUN_BACKUP);
   1264                                 mBackupHandler.sendMessage(msg);
   1265                             } else {
   1266                                 Slog.i(TAG, "Backup time but one already running");
   1267                             }
   1268                         } else {
   1269                             Slog.w(TAG, "Backup pass but e=" + mEnabled + " p=" + mProvisioned);
   1270                         }
   1271                     }
   1272                 }
   1273             }
   1274         }
   1275     }
   1276 
   1277     private class RunInitializeReceiver extends BroadcastReceiver {
   1278         public void onReceive(Context context, Intent intent) {
   1279             if (RUN_INITIALIZE_ACTION.equals(intent.getAction())) {
   1280                 synchronized (mQueueLock) {
   1281                     if (DEBUG) Slog.v(TAG, "Running a device init");
   1282 
   1283                     // Acquire the wakelock and pass it to the init thread.  it will
   1284                     // be released once init concludes.
   1285                     mWakelock.acquire();
   1286 
   1287                     Message msg = mBackupHandler.obtainMessage(MSG_RUN_INITIALIZE);
   1288                     mBackupHandler.sendMessage(msg);
   1289                 }
   1290             }
   1291         }
   1292     }
   1293 
   1294     private void initPackageTracking() {
   1295         if (MORE_DEBUG) Slog.v(TAG, "` tracking");
   1296 
   1297         // Remember our ancestral dataset
   1298         mTokenFile = new File(mBaseStateDir, "ancestral");
   1299         try {
   1300             RandomAccessFile tf = new RandomAccessFile(mTokenFile, "r");
   1301             int version = tf.readInt();
   1302             if (version == CURRENT_ANCESTRAL_RECORD_VERSION) {
   1303                 mAncestralToken = tf.readLong();
   1304                 mCurrentToken = tf.readLong();
   1305 
   1306                 int numPackages = tf.readInt();
   1307                 if (numPackages >= 0) {
   1308                     mAncestralPackages = new HashSet<String>();
   1309                     for (int i = 0; i < numPackages; i++) {
   1310                         String pkgName = tf.readUTF();
   1311                         mAncestralPackages.add(pkgName);
   1312                     }
   1313                 }
   1314             }
   1315             tf.close();
   1316         } catch (FileNotFoundException fnf) {
   1317             // Probably innocuous
   1318             Slog.v(TAG, "No ancestral data");
   1319         } catch (IOException e) {
   1320             Slog.w(TAG, "Unable to read token file", e);
   1321         }
   1322 
   1323         // Keep a log of what apps we've ever backed up.  Because we might have
   1324         // rebooted in the middle of an operation that was removing something from
   1325         // this log, we sanity-check its contents here and reconstruct it.
   1326         mEverStored = new File(mBaseStateDir, "processed");
   1327         File tempProcessedFile = new File(mBaseStateDir, "processed.new");
   1328 
   1329         // If we were in the middle of removing something from the ever-backed-up
   1330         // file, there might be a transient "processed.new" file still present.
   1331         // Ignore it -- we'll validate "processed" against the current package set.
   1332         if (tempProcessedFile.exists()) {
   1333             tempProcessedFile.delete();
   1334         }
   1335 
   1336         // If there are previous contents, parse them out then start a new
   1337         // file to continue the recordkeeping.
   1338         if (mEverStored.exists()) {
   1339             RandomAccessFile temp = null;
   1340             RandomAccessFile in = null;
   1341 
   1342             try {
   1343                 temp = new RandomAccessFile(tempProcessedFile, "rws");
   1344                 in = new RandomAccessFile(mEverStored, "r");
   1345 
   1346                 // Loop until we hit EOF
   1347                 while (true) {
   1348                     String pkg = in.readUTF();
   1349                     try {
   1350                         // is this package still present?
   1351                         mPackageManager.getPackageInfo(pkg, 0);
   1352                         // if we get here then yes it is; remember it
   1353                         mEverStoredApps.add(pkg);
   1354                         temp.writeUTF(pkg);
   1355                         if (MORE_DEBUG) Slog.v(TAG, "   + " + pkg);
   1356                     } catch (NameNotFoundException e) {
   1357                         // nope, this package was uninstalled; don't include it
   1358                         if (MORE_DEBUG) Slog.v(TAG, "   - " + pkg);
   1359                     }
   1360                 }
   1361             } catch (EOFException e) {
   1362                 // Once we've rewritten the backup history log, atomically replace the
   1363                 // old one with the new one then reopen the file for continuing use.
   1364                 if (!tempProcessedFile.renameTo(mEverStored)) {
   1365                     Slog.e(TAG, "Error renaming " + tempProcessedFile + " to " + mEverStored);
   1366                 }
   1367             } catch (IOException e) {
   1368                 Slog.e(TAG, "Error in processed file", e);
   1369             } finally {
   1370                 try { if (temp != null) temp.close(); } catch (IOException e) {}
   1371                 try { if (in != null) in.close(); } catch (IOException e) {}
   1372             }
   1373         }
   1374 
   1375         synchronized (mQueueLock) {
   1376             // Resume the full-data backup queue
   1377             mFullBackupQueue = readFullBackupSchedule();
   1378         }
   1379 
   1380         // Register for broadcasts about package install, etc., so we can
   1381         // update the provider list.
   1382         IntentFilter filter = new IntentFilter();
   1383         filter.addAction(Intent.ACTION_PACKAGE_ADDED);
   1384         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
   1385         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
   1386         filter.addDataScheme("package");
   1387         mContext.registerReceiver(mBroadcastReceiver, filter);
   1388         // Register for events related to sdcard installation.
   1389         IntentFilter sdFilter = new IntentFilter();
   1390         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
   1391         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
   1392         mContext.registerReceiver(mBroadcastReceiver, sdFilter);
   1393     }
   1394 
   1395     private ArrayList<FullBackupEntry> readFullBackupSchedule() {
   1396         boolean changed = false;
   1397         ArrayList<FullBackupEntry> schedule = null;
   1398         List<PackageInfo> apps =
   1399                 PackageManagerBackupAgent.getStorableApplications(mPackageManager);
   1400 
   1401         if (mFullBackupScheduleFile.exists()) {
   1402             FileInputStream fstream = null;
   1403             BufferedInputStream bufStream = null;
   1404             DataInputStream in = null;
   1405             try {
   1406                 fstream = new FileInputStream(mFullBackupScheduleFile);
   1407                 bufStream = new BufferedInputStream(fstream);
   1408                 in = new DataInputStream(bufStream);
   1409 
   1410                 int version = in.readInt();
   1411                 if (version != SCHEDULE_FILE_VERSION) {
   1412                     Slog.e(TAG, "Unknown backup schedule version " + version);
   1413                     return null;
   1414                 }
   1415 
   1416                 final int N = in.readInt();
   1417                 schedule = new ArrayList<FullBackupEntry>(N);
   1418 
   1419                 // HashSet instead of ArraySet specifically because we want the eventual
   1420                 // lookups against O(hundreds) of entries to be as fast as possible, and
   1421                 // we discard the set immediately after the scan so the extra memory
   1422                 // overhead is transient.
   1423                 HashSet<String> foundApps = new HashSet<String>(N);
   1424 
   1425                 for (int i = 0; i < N; i++) {
   1426                     String pkgName = in.readUTF();
   1427                     long lastBackup = in.readLong();
   1428                     foundApps.add(pkgName); // all apps that we've addressed already
   1429                     try {
   1430                         PackageInfo pkg = mPackageManager.getPackageInfo(pkgName, 0);
   1431                         if (appGetsFullBackup(pkg) && appIsEligibleForBackup(pkg.applicationInfo)) {
   1432                             schedule.add(new FullBackupEntry(pkgName, lastBackup));
   1433                         } else {
   1434                             if (DEBUG) {
   1435                                 Slog.i(TAG, "Package " + pkgName
   1436                                         + " no longer eligible for full backup");
   1437                             }
   1438                         }
   1439                     } catch (NameNotFoundException e) {
   1440                         if (DEBUG) {
   1441                             Slog.i(TAG, "Package " + pkgName
   1442                                     + " not installed; dropping from full backup");
   1443                         }
   1444                     }
   1445                 }
   1446 
   1447                 // New apps can arrive "out of band" via OTA and similar, so we also need to
   1448                 // scan to make sure that we're tracking all full-backup candidates properly
   1449                 for (PackageInfo app : apps) {
   1450                     if (appGetsFullBackup(app) && appIsEligibleForBackup(app.applicationInfo)) {
   1451                         if (!foundApps.contains(app.packageName)) {
   1452                             if (MORE_DEBUG) {
   1453                                 Slog.i(TAG, "New full backup app " + app.packageName + " found");
   1454                             }
   1455                             schedule.add(new FullBackupEntry(app.packageName, 0));
   1456                             changed = true;
   1457                         }
   1458                     }
   1459                 }
   1460 
   1461                 Collections.sort(schedule);
   1462             } catch (Exception e) {
   1463                 Slog.e(TAG, "Unable to read backup schedule", e);
   1464                 mFullBackupScheduleFile.delete();
   1465                 schedule = null;
   1466             } finally {
   1467                 IoUtils.closeQuietly(in);
   1468                 IoUtils.closeQuietly(bufStream);
   1469                 IoUtils.closeQuietly(fstream);
   1470             }
   1471         }
   1472 
   1473         if (schedule == null) {
   1474             // no prior queue record, or unable to read it.  Set up the queue
   1475             // from scratch.
   1476             changed = true;
   1477             schedule = new ArrayList<FullBackupEntry>(apps.size());
   1478             for (PackageInfo info : apps) {
   1479                 if (appGetsFullBackup(info) && appIsEligibleForBackup(info.applicationInfo)) {
   1480                     schedule.add(new FullBackupEntry(info.packageName, 0));
   1481                 }
   1482             }
   1483         }
   1484 
   1485         if (changed) {
   1486             writeFullBackupScheduleAsync();
   1487         }
   1488         return schedule;
   1489     }
   1490 
   1491     Runnable mFullBackupScheduleWriter = new Runnable() {
   1492         @Override public void run() {
   1493             synchronized (mQueueLock) {
   1494                 try {
   1495                     ByteArrayOutputStream bufStream = new ByteArrayOutputStream(4096);
   1496                     DataOutputStream bufOut = new DataOutputStream(bufStream);
   1497                     bufOut.writeInt(SCHEDULE_FILE_VERSION);
   1498 
   1499                     // version 1:
   1500                     //
   1501                     // [int] # of packages in the queue = N
   1502                     // N * {
   1503                     //     [utf8] package name
   1504                     //     [long] last backup time for this package
   1505                     //     }
   1506                     int N = mFullBackupQueue.size();
   1507                     bufOut.writeInt(N);
   1508 
   1509                     for (int i = 0; i < N; i++) {
   1510                         FullBackupEntry entry = mFullBackupQueue.get(i);
   1511                         bufOut.writeUTF(entry.packageName);
   1512                         bufOut.writeLong(entry.lastBackup);
   1513                     }
   1514                     bufOut.flush();
   1515 
   1516                     AtomicFile af = new AtomicFile(mFullBackupScheduleFile);
   1517                     FileOutputStream out = af.startWrite();
   1518                     out.write(bufStream.toByteArray());
   1519                     af.finishWrite(out);
   1520                 } catch (Exception e) {
   1521                     Slog.e(TAG, "Unable to write backup schedule!", e);
   1522                 }
   1523             }
   1524         }
   1525     };
   1526 
   1527     private void writeFullBackupScheduleAsync() {
   1528         mBackupHandler.removeCallbacks(mFullBackupScheduleWriter);
   1529         mBackupHandler.post(mFullBackupScheduleWriter);
   1530     }
   1531 
   1532     private void parseLeftoverJournals() {
   1533         for (File f : mJournalDir.listFiles()) {
   1534             if (mJournal == null || f.compareTo(mJournal) != 0) {
   1535                 // This isn't the current journal, so it must be a leftover.  Read
   1536                 // out the package names mentioned there and schedule them for
   1537                 // backup.
   1538                 RandomAccessFile in = null;
   1539                 try {
   1540                     Slog.i(TAG, "Found stale backup journal, scheduling");
   1541                     in = new RandomAccessFile(f, "r");
   1542                     while (true) {
   1543                         String packageName = in.readUTF();
   1544                         if (MORE_DEBUG) Slog.i(TAG, "  " + packageName);
   1545                         dataChangedImpl(packageName);
   1546                     }
   1547                 } catch (EOFException e) {
   1548                     // no more data; we're done
   1549                 } catch (Exception e) {
   1550                     Slog.e(TAG, "Can't read " + f, e);
   1551                 } finally {
   1552                     // close/delete the file
   1553                     try { if (in != null) in.close(); } catch (IOException e) {}
   1554                     f.delete();
   1555                 }
   1556             }
   1557         }
   1558     }
   1559 
   1560     private SecretKey buildPasswordKey(String algorithm, String pw, byte[] salt, int rounds) {
   1561         return buildCharArrayKey(algorithm, pw.toCharArray(), salt, rounds);
   1562     }
   1563 
   1564     private SecretKey buildCharArrayKey(String algorithm, char[] pwArray, byte[] salt, int rounds) {
   1565         try {
   1566             SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm);
   1567             KeySpec ks = new PBEKeySpec(pwArray, salt, rounds, PBKDF2_KEY_SIZE);
   1568             return keyFactory.generateSecret(ks);
   1569         } catch (InvalidKeySpecException e) {
   1570             Slog.e(TAG, "Invalid key spec for PBKDF2!");
   1571         } catch (NoSuchAlgorithmException e) {
   1572             Slog.e(TAG, "PBKDF2 unavailable!");
   1573         }
   1574         return null;
   1575     }
   1576 
   1577     private String buildPasswordHash(String algorithm, String pw, byte[] salt, int rounds) {
   1578         SecretKey key = buildPasswordKey(algorithm, pw, salt, rounds);
   1579         if (key != null) {
   1580             return byteArrayToHex(key.getEncoded());
   1581         }
   1582         return null;
   1583     }
   1584 
   1585     private String byteArrayToHex(byte[] data) {
   1586         StringBuilder buf = new StringBuilder(data.length * 2);
   1587         for (int i = 0; i < data.length; i++) {
   1588             buf.append(Byte.toHexString(data[i], true));
   1589         }
   1590         return buf.toString();
   1591     }
   1592 
   1593     private byte[] hexToByteArray(String digits) {
   1594         final int bytes = digits.length() / 2;
   1595         if (2*bytes != digits.length()) {
   1596             throw new IllegalArgumentException("Hex string must have an even number of digits");
   1597         }
   1598 
   1599         byte[] result = new byte[bytes];
   1600         for (int i = 0; i < digits.length(); i += 2) {
   1601             result[i/2] = (byte) Integer.parseInt(digits.substring(i, i+2), 16);
   1602         }
   1603         return result;
   1604     }
   1605 
   1606     private byte[] makeKeyChecksum(String algorithm, byte[] pwBytes, byte[] salt, int rounds) {
   1607         char[] mkAsChar = new char[pwBytes.length];
   1608         for (int i = 0; i < pwBytes.length; i++) {
   1609             mkAsChar[i] = (char) pwBytes[i];
   1610         }
   1611 
   1612         Key checksum = buildCharArrayKey(algorithm, mkAsChar, salt, rounds);
   1613         return checksum.getEncoded();
   1614     }
   1615 
   1616     // Used for generating random salts or passwords
   1617     private byte[] randomBytes(int bits) {
   1618         byte[] array = new byte[bits / 8];
   1619         mRng.nextBytes(array);
   1620         return array;
   1621     }
   1622 
   1623     boolean passwordMatchesSaved(String algorithm, String candidatePw, int rounds) {
   1624         if (mPasswordHash == null) {
   1625             // no current password case -- require that 'currentPw' be null or empty
   1626             if (candidatePw == null || "".equals(candidatePw)) {
   1627                 return true;
   1628             } // else the non-empty candidate does not match the empty stored pw
   1629         } else {
   1630             // hash the stated current pw and compare to the stored one
   1631             if (candidatePw != null && candidatePw.length() > 0) {
   1632                 String currentPwHash = buildPasswordHash(algorithm, candidatePw, mPasswordSalt, rounds);
   1633                 if (mPasswordHash.equalsIgnoreCase(currentPwHash)) {
   1634                     // candidate hash matches the stored hash -- the password matches
   1635                     return true;
   1636                 }
   1637             } // else the stored pw is nonempty but the candidate is empty; no match
   1638         }
   1639         return false;
   1640     }
   1641 
   1642     public boolean setBackupPassword(String currentPw, String newPw) {
   1643         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   1644                 "setBackupPassword");
   1645 
   1646         // When processing v1 passwords we may need to try two different PBKDF2 checksum regimes
   1647         final boolean pbkdf2Fallback = (mPasswordVersion < BACKUP_PW_FILE_VERSION);
   1648 
   1649         // If the supplied pw doesn't hash to the the saved one, fail.  The password
   1650         // might be caught in the legacy crypto mismatch; verify that too.
   1651         if (!passwordMatchesSaved(PBKDF_CURRENT, currentPw, PBKDF2_HASH_ROUNDS)
   1652                 && !(pbkdf2Fallback && passwordMatchesSaved(PBKDF_FALLBACK,
   1653                         currentPw, PBKDF2_HASH_ROUNDS))) {
   1654             return false;
   1655         }
   1656 
   1657         // Snap up to current on the pw file version
   1658         mPasswordVersion = BACKUP_PW_FILE_VERSION;
   1659         FileOutputStream pwFout = null;
   1660         DataOutputStream pwOut = null;
   1661         try {
   1662             pwFout = new FileOutputStream(mPasswordVersionFile);
   1663             pwOut = new DataOutputStream(pwFout);
   1664             pwOut.writeInt(mPasswordVersion);
   1665         } catch (IOException e) {
   1666             Slog.e(TAG, "Unable to write backup pw version; password not changed");
   1667             return false;
   1668         } finally {
   1669             try {
   1670                 if (pwOut != null) pwOut.close();
   1671                 if (pwFout != null) pwFout.close();
   1672             } catch (IOException e) {
   1673                 Slog.w(TAG, "Unable to close pw version record");
   1674             }
   1675         }
   1676 
   1677         // Clearing the password is okay
   1678         if (newPw == null || newPw.isEmpty()) {
   1679             if (mPasswordHashFile.exists()) {
   1680                 if (!mPasswordHashFile.delete()) {
   1681                     // Unable to delete the old pw file, so fail
   1682                     Slog.e(TAG, "Unable to clear backup password");
   1683                     return false;
   1684                 }
   1685             }
   1686             mPasswordHash = null;
   1687             mPasswordSalt = null;
   1688             return true;
   1689         }
   1690 
   1691         try {
   1692             // Okay, build the hash of the new backup password
   1693             byte[] salt = randomBytes(PBKDF2_SALT_SIZE);
   1694             String newPwHash = buildPasswordHash(PBKDF_CURRENT, newPw, salt, PBKDF2_HASH_ROUNDS);
   1695 
   1696             OutputStream pwf = null, buffer = null;
   1697             DataOutputStream out = null;
   1698             try {
   1699                 pwf = new FileOutputStream(mPasswordHashFile);
   1700                 buffer = new BufferedOutputStream(pwf);
   1701                 out = new DataOutputStream(buffer);
   1702                 // integer length of the salt array, followed by the salt,
   1703                 // then the hex pw hash string
   1704                 out.writeInt(salt.length);
   1705                 out.write(salt);
   1706                 out.writeUTF(newPwHash);
   1707                 out.flush();
   1708                 mPasswordHash = newPwHash;
   1709                 mPasswordSalt = salt;
   1710                 return true;
   1711             } finally {
   1712                 if (out != null) out.close();
   1713                 if (buffer != null) buffer.close();
   1714                 if (pwf != null) pwf.close();
   1715             }
   1716         } catch (IOException e) {
   1717             Slog.e(TAG, "Unable to set backup password");
   1718         }
   1719         return false;
   1720     }
   1721 
   1722     public boolean hasBackupPassword() {
   1723         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   1724                 "hasBackupPassword");
   1725 
   1726         return mPasswordHash != null && mPasswordHash.length() > 0;
   1727     }
   1728 
   1729     private boolean backupPasswordMatches(String currentPw) {
   1730         if (hasBackupPassword()) {
   1731             final boolean pbkdf2Fallback = (mPasswordVersion < BACKUP_PW_FILE_VERSION);
   1732             if (!passwordMatchesSaved(PBKDF_CURRENT, currentPw, PBKDF2_HASH_ROUNDS)
   1733                     && !(pbkdf2Fallback && passwordMatchesSaved(PBKDF_FALLBACK,
   1734                             currentPw, PBKDF2_HASH_ROUNDS))) {
   1735                 if (DEBUG) Slog.w(TAG, "Backup password mismatch; aborting");
   1736                 return false;
   1737             }
   1738         }
   1739         return true;
   1740     }
   1741 
   1742     // Maintain persistent state around whether need to do an initialize operation.
   1743     // Must be called with the queue lock held.
   1744     void recordInitPendingLocked(boolean isPending, String transportName) {
   1745         if (MORE_DEBUG) Slog.i(TAG, "recordInitPendingLocked: " + isPending
   1746                 + " on transport " + transportName);
   1747         mBackupHandler.removeMessages(MSG_RETRY_INIT);
   1748 
   1749         try {
   1750             IBackupTransport transport = getTransport(transportName);
   1751             if (transport != null) {
   1752                 String transportDirName = transport.transportDirName();
   1753                 File stateDir = new File(mBaseStateDir, transportDirName);
   1754                 File initPendingFile = new File(stateDir, INIT_SENTINEL_FILE_NAME);
   1755 
   1756                 if (isPending) {
   1757                     // We need an init before we can proceed with sending backup data.
   1758                     // Record that with an entry in our set of pending inits, as well as
   1759                     // journaling it via creation of a sentinel file.
   1760                     mPendingInits.add(transportName);
   1761                     try {
   1762                         (new FileOutputStream(initPendingFile)).close();
   1763                     } catch (IOException ioe) {
   1764                         // Something is badly wrong with our permissions; just try to move on
   1765                     }
   1766                 } else {
   1767                     // No more initialization needed; wipe the journal and reset our state.
   1768                     initPendingFile.delete();
   1769                     mPendingInits.remove(transportName);
   1770                 }
   1771                 return; // done; don't fall through to the error case
   1772             }
   1773         } catch (Exception e) {
   1774             // transport threw when asked its name; fall through to the lookup-failed case
   1775             Slog.e(TAG, "Transport " + transportName + " failed to report name: "
   1776                     + e.getMessage());
   1777         }
   1778 
   1779         // The named transport doesn't exist or threw.  This operation is
   1780         // important, so we record the need for a an init and post a message
   1781         // to retry the init later.
   1782         if (isPending) {
   1783             mPendingInits.add(transportName);
   1784             mBackupHandler.sendMessageDelayed(
   1785                     mBackupHandler.obtainMessage(MSG_RETRY_INIT,
   1786                             (isPending ? 1 : 0),
   1787                             0,
   1788                             transportName),
   1789                     TRANSPORT_RETRY_INTERVAL);
   1790         }
   1791     }
   1792 
   1793     // Reset all of our bookkeeping, in response to having been told that
   1794     // the backend data has been wiped [due to idle expiry, for example],
   1795     // so we must re-upload all saved settings.
   1796     void resetBackupState(File stateFileDir) {
   1797         synchronized (mQueueLock) {
   1798             // Wipe the "what we've ever backed up" tracking
   1799             mEverStoredApps.clear();
   1800             mEverStored.delete();
   1801 
   1802             mCurrentToken = 0;
   1803             writeRestoreTokens();
   1804 
   1805             // Remove all the state files
   1806             for (File sf : stateFileDir.listFiles()) {
   1807                 // ... but don't touch the needs-init sentinel
   1808                 if (!sf.getName().equals(INIT_SENTINEL_FILE_NAME)) {
   1809                     sf.delete();
   1810                 }
   1811             }
   1812         }
   1813 
   1814         // Enqueue a new backup of every participant
   1815         synchronized (mBackupParticipants) {
   1816             final int N = mBackupParticipants.size();
   1817             for (int i=0; i<N; i++) {
   1818                 HashSet<String> participants = mBackupParticipants.valueAt(i);
   1819                 if (participants != null) {
   1820                     for (String packageName : participants) {
   1821                         dataChangedImpl(packageName);
   1822                     }
   1823                 }
   1824             }
   1825         }
   1826     }
   1827 
   1828     // Add a transport to our set of available backends.  If 'transport' is null, this
   1829     // is an unregistration, and the transport's entry is removed from our bookkeeping.
   1830     private void registerTransport(String name, String component, IBackupTransport transport) {
   1831         synchronized (mTransports) {
   1832             if (DEBUG) Slog.v(TAG, "Registering transport "
   1833                     + component + "::" + name + " = " + transport);
   1834             if (transport != null) {
   1835                 mTransports.put(name, transport);
   1836                 mTransportNames.put(component, name);
   1837             } else {
   1838                 mTransports.remove(mTransportNames.get(component));
   1839                 mTransportNames.remove(component);
   1840                 // Nothing further to do in the unregistration case
   1841                 return;
   1842             }
   1843         }
   1844 
   1845         // If the init sentinel file exists, we need to be sure to perform the init
   1846         // as soon as practical.  We also create the state directory at registration
   1847         // time to ensure it's present from the outset.
   1848         try {
   1849             String transportName = transport.transportDirName();
   1850             File stateDir = new File(mBaseStateDir, transportName);
   1851             stateDir.mkdirs();
   1852 
   1853             File initSentinel = new File(stateDir, INIT_SENTINEL_FILE_NAME);
   1854             if (initSentinel.exists()) {
   1855                 synchronized (mQueueLock) {
   1856                     mPendingInits.add(name);
   1857 
   1858                     // TODO: pick a better starting time than now + 1 minute
   1859                     long delay = 1000 * 60; // one minute, in milliseconds
   1860                     mAlarmManager.set(AlarmManager.RTC_WAKEUP,
   1861                             System.currentTimeMillis() + delay, mRunInitIntent);
   1862                 }
   1863             }
   1864         } catch (Exception e) {
   1865             // the transport threw when asked its file naming prefs; declare it invalid
   1866             Slog.e(TAG, "Unable to register transport as " + name);
   1867             mTransportNames.remove(component);
   1868             mTransports.remove(name);
   1869         }
   1870     }
   1871 
   1872     // ----- Track installation/removal of packages -----
   1873     BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
   1874         public void onReceive(Context context, Intent intent) {
   1875             if (MORE_DEBUG) Slog.d(TAG, "Received broadcast " + intent);
   1876 
   1877             String action = intent.getAction();
   1878             boolean replacing = false;
   1879             boolean added = false;
   1880             boolean changed = false;
   1881             Bundle extras = intent.getExtras();
   1882             String pkgList[] = null;
   1883             if (Intent.ACTION_PACKAGE_ADDED.equals(action) ||
   1884                     Intent.ACTION_PACKAGE_REMOVED.equals(action) ||
   1885                     Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
   1886                 Uri uri = intent.getData();
   1887                 if (uri == null) {
   1888                     return;
   1889                 }
   1890                 String pkgName = uri.getSchemeSpecificPart();
   1891                 if (pkgName != null) {
   1892                     pkgList = new String[] { pkgName };
   1893                 }
   1894                 changed = Intent.ACTION_PACKAGE_CHANGED.equals(action);
   1895 
   1896                 // At package-changed we only care about looking at new transport states
   1897                 if (changed) {
   1898                     try {
   1899                         String[] components =
   1900                                 intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
   1901 
   1902                         if (MORE_DEBUG) {
   1903                             Slog.i(TAG, "Package " + pkgName + " changed; rechecking");
   1904                             for (int i = 0; i < components.length; i++) {
   1905                                 Slog.i(TAG, "   * " + components[i]);
   1906                             }
   1907                         }
   1908 
   1909                         // In general we need to try to bind any time we see a component enable
   1910                         // state change, because that change may have made a transport available.
   1911                         // However, because we currently only support a single transport component
   1912                         // per package, we can skip the bind attempt if the change (a) affects a
   1913                         // package known to host a transport, but (b) does not affect the known
   1914                         // transport component itself.
   1915                         //
   1916                         // In addition, if the change *is* to a known transport component, we need
   1917                         // to unbind it before retrying the binding.
   1918                         boolean tryBind = true;
   1919                         synchronized (mTransports) {
   1920                             TransportConnection conn = mTransportConnections.get(pkgName);
   1921                             if (conn != null) {
   1922                                 // We have a bound transport in this package; do we need to rebind it?
   1923                                 final ServiceInfo svc = conn.mTransport;
   1924                                 ComponentName svcName =
   1925                                         new ComponentName(svc.packageName, svc.name);
   1926                                 if (svc.packageName.equals(pkgName)) {
   1927                                     final String className = svcName.getClassName();
   1928                                     if (MORE_DEBUG) {
   1929                                         Slog.i(TAG, "Checking need to rebind " + className);
   1930                                     }
   1931                                     // See whether it's the transport component within this package
   1932                                     boolean isTransport = false;
   1933                                     for (int i = 0; i < components.length; i++) {
   1934                                         if (className.equals(components[i])) {
   1935                                             // Okay, it's an existing transport component.
   1936                                             final String flatName = svcName.flattenToShortString();
   1937                                             mContext.unbindService(conn);
   1938                                             mTransportConnections.remove(pkgName);
   1939                                             mTransports.remove(mTransportNames.get(flatName));
   1940                                             mTransportNames.remove(flatName);
   1941                                             isTransport = true;
   1942                                             break;
   1943                                         }
   1944                                     }
   1945                                     if (!isTransport) {
   1946                                         // A non-transport component within a package that is hosting
   1947                                         // a bound transport
   1948                                         tryBind = false;
   1949                                     }
   1950                                 }
   1951                             }
   1952                         }
   1953                         // and now (re)bind as appropriate
   1954                         if (tryBind) {
   1955                             if (MORE_DEBUG) {
   1956                                 Slog.i(TAG, "Yes, need to recheck binding");
   1957                             }
   1958                             PackageInfo app = mPackageManager.getPackageInfo(pkgName, 0);
   1959                             checkForTransportAndBind(app);
   1960                         }
   1961                     } catch (NameNotFoundException e) {
   1962                         // Nope, can't find it - just ignore
   1963                         if (MORE_DEBUG) {
   1964                             Slog.w(TAG, "Can't find changed package " + pkgName);
   1965                         }
   1966                     }
   1967                     return; // nothing more to do in the PACKAGE_CHANGED case
   1968                 }
   1969 
   1970                 added = Intent.ACTION_PACKAGE_ADDED.equals(action);
   1971                 replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false);
   1972             } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
   1973                 added = true;
   1974                 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
   1975             } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
   1976                 added = false;
   1977                 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
   1978             }
   1979 
   1980             if (pkgList == null || pkgList.length == 0) {
   1981                 return;
   1982             }
   1983 
   1984             final int uid = extras.getInt(Intent.EXTRA_UID);
   1985             if (added) {
   1986                 synchronized (mBackupParticipants) {
   1987                     if (replacing) {
   1988                         // This is the package-replaced case; we just remove the entry
   1989                         // under the old uid and fall through to re-add.  If an app
   1990                         // just added key/value backup participation, this picks it up
   1991                         // as a known participant.
   1992                         removePackageParticipantsLocked(pkgList, uid);
   1993                     }
   1994                     addPackageParticipantsLocked(pkgList);
   1995                 }
   1996                 // If they're full-backup candidates, add them there instead
   1997                 final long now = System.currentTimeMillis();
   1998                 for (String packageName : pkgList) {
   1999                     try {
   2000                         PackageInfo app = mPackageManager.getPackageInfo(packageName, 0);
   2001                         if (appGetsFullBackup(app) && appIsEligibleForBackup(app.applicationInfo)) {
   2002                             enqueueFullBackup(packageName, now);
   2003                             scheduleNextFullBackupJob(0);
   2004                         } else {
   2005                             // The app might have just transitioned out of full-data into
   2006                             // doing key/value backups, or might have just disabled backups
   2007                             // entirely.  Make sure it is no longer in the full-data queue.
   2008                             synchronized (mQueueLock) {
   2009                                 dequeueFullBackupLocked(packageName);
   2010                             }
   2011                             writeFullBackupScheduleAsync();
   2012                         }
   2013 
   2014                         // Transport maintenance: rebind to known existing transports that have
   2015                         // just been updated; and bind to any newly-installed transport services.
   2016                         synchronized (mTransports) {
   2017                             final TransportConnection conn = mTransportConnections.get(packageName);
   2018                             if (conn != null) {
   2019                                 if (MORE_DEBUG) {
   2020                                     Slog.i(TAG, "Transport package changed; rebinding");
   2021                                 }
   2022                                 bindTransport(conn.mTransport);
   2023                             } else {
   2024                                 checkForTransportAndBind(app);
   2025                             }
   2026                         }
   2027 
   2028                     } catch (NameNotFoundException e) {
   2029                         // doesn't really exist; ignore it
   2030                         if (DEBUG) {
   2031                             Slog.w(TAG, "Can't resolve new app " + packageName);
   2032                         }
   2033                     }
   2034                 }
   2035 
   2036                 // Whenever a package is added or updated we need to update
   2037                 // the package metadata bookkeeping.
   2038                 dataChangedImpl(PACKAGE_MANAGER_SENTINEL);
   2039             } else {
   2040                 if (replacing) {
   2041                     // The package is being updated.  We'll receive a PACKAGE_ADDED shortly.
   2042                 } else {
   2043                     // Outright removal.  In the full-data case, the app will be dropped
   2044                     // from the queue when its (now obsolete) name comes up again for
   2045                     // backup.
   2046                     synchronized (mBackupParticipants) {
   2047                         removePackageParticipantsLocked(pkgList, uid);
   2048                     }
   2049                 }
   2050             }
   2051         }
   2052     };
   2053 
   2054     // ----- Track connection to transports service -----
   2055     class TransportConnection implements ServiceConnection {
   2056         ServiceInfo mTransport;
   2057 
   2058         public TransportConnection(ServiceInfo transport) {
   2059             mTransport = transport;
   2060         }
   2061 
   2062         @Override
   2063         public void onServiceConnected(ComponentName component, IBinder service) {
   2064             if (DEBUG) Slog.v(TAG, "Connected to transport " + component);
   2065             final String name = component.flattenToShortString();
   2066             try {
   2067                 IBackupTransport transport = IBackupTransport.Stub.asInterface(service);
   2068                 registerTransport(transport.name(), name, transport);
   2069                 EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE, name, 1);
   2070             } catch (Exception e) {
   2071                 Slog.e(TAG, "Unable to register transport " + component
   2072                         + ": " + e.getMessage());
   2073                 EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE, name, 0);
   2074             }
   2075         }
   2076 
   2077         @Override
   2078         public void onServiceDisconnected(ComponentName component) {
   2079             if (DEBUG) Slog.v(TAG, "Disconnected from transport " + component);
   2080             final String name = component.flattenToShortString();
   2081             EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE, name, 0);
   2082             registerTransport(null, name, null);
   2083         }
   2084     };
   2085 
   2086     // Check whether the given package hosts a transport, and bind if so
   2087     void checkForTransportAndBind(PackageInfo pkgInfo) {
   2088         Intent intent = new Intent(mTransportServiceIntent)
   2089                 .setPackage(pkgInfo.packageName);
   2090         // TODO: http://b/22388012
   2091         List<ResolveInfo> hosts = mPackageManager.queryIntentServicesAsUser(
   2092                 intent, 0, UserHandle.USER_SYSTEM);
   2093         if (hosts != null) {
   2094             final int N = hosts.size();
   2095             for (int i = 0; i < N; i++) {
   2096                 final ServiceInfo info = hosts.get(i).serviceInfo;
   2097                 tryBindTransport(info);
   2098             }
   2099         }
   2100     }
   2101 
   2102     // Verify that the service exists and is hosted by a privileged app, then proceed to bind
   2103     boolean tryBindTransport(ServiceInfo info) {
   2104         try {
   2105             PackageInfo packInfo = mPackageManager.getPackageInfo(info.packageName, 0);
   2106             if ((packInfo.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
   2107                     != 0) {
   2108                 return bindTransport(info);
   2109             } else {
   2110                 Slog.w(TAG, "Transport package " + info.packageName + " not privileged");
   2111             }
   2112         } catch (NameNotFoundException e) {
   2113             Slog.w(TAG, "Problem resolving transport package " + info.packageName);
   2114         }
   2115         return false;
   2116     }
   2117 
   2118     // Actually bind; presumes that we have already validated the transport service
   2119     boolean bindTransport(ServiceInfo transport) {
   2120         ComponentName svcName = new ComponentName(transport.packageName, transport.name);
   2121         if (!mTransportWhitelist.contains(svcName)) {
   2122             Slog.w(TAG, "Proposed transport " + svcName + " not whitelisted; ignoring");
   2123             return false;
   2124         }
   2125 
   2126         if (MORE_DEBUG) {
   2127             Slog.i(TAG, "Binding to transport host " + svcName);
   2128         }
   2129         Intent intent = new Intent(mTransportServiceIntent);
   2130         intent.setComponent(svcName);
   2131 
   2132         TransportConnection connection;
   2133         synchronized (mTransports) {
   2134             connection = mTransportConnections.get(transport.packageName);
   2135             if (null == connection) {
   2136                 connection = new TransportConnection(transport);
   2137                 mTransportConnections.put(transport.packageName, connection);
   2138             } else {
   2139                 // This is a rebind due to package upgrade.  The service won't be
   2140                 // automatically relaunched for us until we explicitly rebind, but
   2141                 // we need to unbind the now-orphaned original connection.
   2142                 mContext.unbindService(connection);
   2143             }
   2144         }
   2145         // TODO: http://b/22388012
   2146         return mContext.bindServiceAsUser(intent,
   2147                 connection, Context.BIND_AUTO_CREATE,
   2148                 UserHandle.SYSTEM);
   2149     }
   2150 
   2151     // Add the backup agents in the given packages to our set of known backup participants.
   2152     // If 'packageNames' is null, adds all backup agents in the whole system.
   2153     void addPackageParticipantsLocked(String[] packageNames) {
   2154         // Look for apps that define the android:backupAgent attribute
   2155         List<PackageInfo> targetApps = allAgentPackages();
   2156         if (packageNames != null) {
   2157             if (MORE_DEBUG) Slog.v(TAG, "addPackageParticipantsLocked: #" + packageNames.length);
   2158             for (String packageName : packageNames) {
   2159                 addPackageParticipantsLockedInner(packageName, targetApps);
   2160             }
   2161         } else {
   2162             if (MORE_DEBUG) Slog.v(TAG, "addPackageParticipantsLocked: all");
   2163             addPackageParticipantsLockedInner(null, targetApps);
   2164         }
   2165     }
   2166 
   2167     private void addPackageParticipantsLockedInner(String packageName,
   2168             List<PackageInfo> targetPkgs) {
   2169         if (MORE_DEBUG) {
   2170             Slog.v(TAG, "Examining " + packageName + " for backup agent");
   2171         }
   2172 
   2173         for (PackageInfo pkg : targetPkgs) {
   2174             if (packageName == null || pkg.packageName.equals(packageName)) {
   2175                 int uid = pkg.applicationInfo.uid;
   2176                 HashSet<String> set = mBackupParticipants.get(uid);
   2177                 if (set == null) {
   2178                     set = new HashSet<>();
   2179                     mBackupParticipants.put(uid, set);
   2180                 }
   2181                 set.add(pkg.packageName);
   2182                 if (MORE_DEBUG) Slog.v(TAG, "Agent found; added");
   2183 
   2184                 // Schedule a backup for it on general principles
   2185                 if (MORE_DEBUG) Slog.i(TAG, "Scheduling backup for new app " + pkg.packageName);
   2186                 Message msg = mBackupHandler
   2187                         .obtainMessage(MSG_SCHEDULE_BACKUP_PACKAGE, pkg.packageName);
   2188                 mBackupHandler.sendMessage(msg);
   2189             }
   2190         }
   2191     }
   2192 
   2193     // Remove the given packages' entries from our known active set.
   2194     void removePackageParticipantsLocked(String[] packageNames, int oldUid) {
   2195         if (packageNames == null) {
   2196             Slog.w(TAG, "removePackageParticipants with null list");
   2197             return;
   2198         }
   2199 
   2200         if (MORE_DEBUG) Slog.v(TAG, "removePackageParticipantsLocked: uid=" + oldUid
   2201                 + " #" + packageNames.length);
   2202         for (String pkg : packageNames) {
   2203             // Known previous UID, so we know which package set to check
   2204             HashSet<String> set = mBackupParticipants.get(oldUid);
   2205             if (set != null && set.contains(pkg)) {
   2206                 removePackageFromSetLocked(set, pkg);
   2207                 if (set.isEmpty()) {
   2208                     if (MORE_DEBUG) Slog.v(TAG, "  last one of this uid; purging set");
   2209                     mBackupParticipants.remove(oldUid);
   2210                 }
   2211             }
   2212         }
   2213     }
   2214 
   2215     private void removePackageFromSetLocked(final HashSet<String> set,
   2216             final String packageName) {
   2217         if (set.contains(packageName)) {
   2218             // Found it.  Remove this one package from the bookkeeping, and
   2219             // if it's the last participating app under this uid we drop the
   2220             // (now-empty) set as well.
   2221             // Note that we deliberately leave it 'known' in the "ever backed up"
   2222             // bookkeeping so that its current-dataset data will be retrieved
   2223             // if the app is subsequently reinstalled
   2224             if (MORE_DEBUG) Slog.v(TAG, "  removing participant " + packageName);
   2225             set.remove(packageName);
   2226             mPendingBackups.remove(packageName);
   2227         }
   2228     }
   2229 
   2230     // Returns the set of all applications that define an android:backupAgent attribute
   2231     List<PackageInfo> allAgentPackages() {
   2232         // !!! TODO: cache this and regenerate only when necessary
   2233         int flags = PackageManager.GET_SIGNATURES;
   2234         List<PackageInfo> packages = mPackageManager.getInstalledPackages(flags);
   2235         int N = packages.size();
   2236         for (int a = N-1; a >= 0; a--) {
   2237             PackageInfo pkg = packages.get(a);
   2238             try {
   2239                 ApplicationInfo app = pkg.applicationInfo;
   2240                 if (((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0)
   2241                         || app.backupAgentName == null
   2242                         || (app.flags&ApplicationInfo.FLAG_FULL_BACKUP_ONLY) != 0) {
   2243                     packages.remove(a);
   2244                 }
   2245                 else {
   2246                     // we will need the shared library path, so look that up and store it here.
   2247                     // This is used implicitly when we pass the PackageInfo object off to
   2248                     // the Activity Manager to launch the app for backup/restore purposes.
   2249                     app = mPackageManager.getApplicationInfo(pkg.packageName,
   2250                             PackageManager.GET_SHARED_LIBRARY_FILES);
   2251                     pkg.applicationInfo.sharedLibraryFiles = app.sharedLibraryFiles;
   2252                 }
   2253             } catch (NameNotFoundException e) {
   2254                 packages.remove(a);
   2255             }
   2256         }
   2257         return packages;
   2258     }
   2259 
   2260     // Called from the backup tasks: record that the given app has been successfully
   2261     // backed up at least once.  This includes both key/value and full-data backups
   2262     // through the transport.
   2263     void logBackupComplete(String packageName) {
   2264         if (packageName.equals(PACKAGE_MANAGER_SENTINEL)) return;
   2265 
   2266         synchronized (mEverStoredApps) {
   2267             if (!mEverStoredApps.add(packageName)) return;
   2268 
   2269             RandomAccessFile out = null;
   2270             try {
   2271                 out = new RandomAccessFile(mEverStored, "rws");
   2272                 out.seek(out.length());
   2273                 out.writeUTF(packageName);
   2274             } catch (IOException e) {
   2275                 Slog.e(TAG, "Can't log backup of " + packageName + " to " + mEverStored);
   2276             } finally {
   2277                 try { if (out != null) out.close(); } catch (IOException e) {}
   2278             }
   2279         }
   2280     }
   2281 
   2282     // Remove our awareness of having ever backed up the given package
   2283     void removeEverBackedUp(String packageName) {
   2284         if (DEBUG) Slog.v(TAG, "Removing backed-up knowledge of " + packageName);
   2285         if (MORE_DEBUG) Slog.v(TAG, "New set:");
   2286 
   2287         synchronized (mEverStoredApps) {
   2288             // Rewrite the file and rename to overwrite.  If we reboot in the middle,
   2289             // we'll recognize on initialization time that the package no longer
   2290             // exists and fix it up then.
   2291             File tempKnownFile = new File(mBaseStateDir, "processed.new");
   2292             RandomAccessFile known = null;
   2293             try {
   2294                 known = new RandomAccessFile(tempKnownFile, "rws");
   2295                 mEverStoredApps.remove(packageName);
   2296                 for (String s : mEverStoredApps) {
   2297                     known.writeUTF(s);
   2298                     if (MORE_DEBUG) Slog.v(TAG, "    " + s);
   2299                 }
   2300                 known.close();
   2301                 known = null;
   2302                 if (!tempKnownFile.renameTo(mEverStored)) {
   2303                     throw new IOException("Can't rename " + tempKnownFile + " to " + mEverStored);
   2304                 }
   2305             } catch (IOException e) {
   2306                 // Bad: we couldn't create the new copy.  For safety's sake we
   2307                 // abandon the whole process and remove all what's-backed-up
   2308                 // state entirely, meaning we'll force a backup pass for every
   2309                 // participant on the next boot or [re]install.
   2310                 Slog.w(TAG, "Error rewriting " + mEverStored, e);
   2311                 mEverStoredApps.clear();
   2312                 tempKnownFile.delete();
   2313                 mEverStored.delete();
   2314             } finally {
   2315                 try { if (known != null) known.close(); } catch (IOException e) {}
   2316             }
   2317         }
   2318     }
   2319 
   2320     // Persistently record the current and ancestral backup tokens as well
   2321     // as the set of packages with data [supposedly] available in the
   2322     // ancestral dataset.
   2323     void writeRestoreTokens() {
   2324         try {
   2325             RandomAccessFile af = new RandomAccessFile(mTokenFile, "rwd");
   2326 
   2327             // First, the version number of this record, for futureproofing
   2328             af.writeInt(CURRENT_ANCESTRAL_RECORD_VERSION);
   2329 
   2330             // Write the ancestral and current tokens
   2331             af.writeLong(mAncestralToken);
   2332             af.writeLong(mCurrentToken);
   2333 
   2334             // Now write the set of ancestral packages
   2335             if (mAncestralPackages == null) {
   2336                 af.writeInt(-1);
   2337             } else {
   2338                 af.writeInt(mAncestralPackages.size());
   2339                 if (DEBUG) Slog.v(TAG, "Ancestral packages:  " + mAncestralPackages.size());
   2340                 for (String pkgName : mAncestralPackages) {
   2341                     af.writeUTF(pkgName);
   2342                     if (MORE_DEBUG) Slog.v(TAG, "   " + pkgName);
   2343                 }
   2344             }
   2345             af.close();
   2346         } catch (IOException e) {
   2347             Slog.w(TAG, "Unable to write token file:", e);
   2348         }
   2349     }
   2350 
   2351     // Return the given transport
   2352     private IBackupTransport getTransport(String transportName) {
   2353         synchronized (mTransports) {
   2354             IBackupTransport transport = mTransports.get(transportName);
   2355             if (transport == null) {
   2356                 Slog.w(TAG, "Requested unavailable transport: " + transportName);
   2357             }
   2358             return transport;
   2359         }
   2360     }
   2361 
   2362     // What name is this transport registered under...?
   2363     private String getTransportName(IBackupTransport transport) {
   2364         if (MORE_DEBUG) {
   2365             Slog.v(TAG, "Searching for transport name of " + transport);
   2366         }
   2367         synchronized (mTransports) {
   2368             final int N = mTransports.size();
   2369             for (int i = 0; i < N; i++) {
   2370                 if (mTransports.valueAt(i).equals(transport)) {
   2371                     if (MORE_DEBUG) {
   2372                         Slog.v(TAG, "  Name found: " + mTransports.keyAt(i));
   2373                     }
   2374                     return mTransports.keyAt(i);
   2375                 }
   2376             }
   2377         }
   2378         return null;
   2379     }
   2380 
   2381     // fire off a backup agent, blocking until it attaches or times out
   2382     IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode) {
   2383         IBackupAgent agent = null;
   2384         synchronized(mAgentConnectLock) {
   2385             mConnecting = true;
   2386             mConnectedAgent = null;
   2387             try {
   2388                 if (mActivityManager.bindBackupAgent(app.packageName, mode,
   2389                         UserHandle.USER_OWNER)) {
   2390                     Slog.d(TAG, "awaiting agent for " + app);
   2391 
   2392                     // success; wait for the agent to arrive
   2393                     // only wait 10 seconds for the bind to happen
   2394                     long timeoutMark = System.currentTimeMillis() + TIMEOUT_INTERVAL;
   2395                     while (mConnecting && mConnectedAgent == null
   2396                             && (System.currentTimeMillis() < timeoutMark)) {
   2397                         try {
   2398                             mAgentConnectLock.wait(5000);
   2399                         } catch (InterruptedException e) {
   2400                             // just bail
   2401                             Slog.w(TAG, "Interrupted: " + e);
   2402                             mActivityManager.clearPendingBackup();
   2403                             return null;
   2404                         }
   2405                     }
   2406 
   2407                     // if we timed out with no connect, abort and move on
   2408                     if (mConnecting == true) {
   2409                         Slog.w(TAG, "Timeout waiting for agent " + app);
   2410                         mActivityManager.clearPendingBackup();
   2411                         return null;
   2412                     }
   2413                     if (DEBUG) Slog.i(TAG, "got agent " + mConnectedAgent);
   2414                     agent = mConnectedAgent;
   2415                 }
   2416             } catch (RemoteException e) {
   2417                 // can't happen - ActivityManager is local
   2418             }
   2419         }
   2420         return agent;
   2421     }
   2422 
   2423     // clear an application's data, blocking until the operation completes or times out
   2424     void clearApplicationDataSynchronous(String packageName) {
   2425         // Don't wipe packages marked allowClearUserData=false
   2426         try {
   2427             PackageInfo info = mPackageManager.getPackageInfo(packageName, 0);
   2428             if ((info.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA) == 0) {
   2429                 if (MORE_DEBUG) Slog.i(TAG, "allowClearUserData=false so not wiping "
   2430                         + packageName);
   2431                 return;
   2432             }
   2433         } catch (NameNotFoundException e) {
   2434             Slog.w(TAG, "Tried to clear data for " + packageName + " but not found");
   2435             return;
   2436         }
   2437 
   2438         ClearDataObserver observer = new ClearDataObserver();
   2439 
   2440         synchronized(mClearDataLock) {
   2441             mClearingData = true;
   2442             try {
   2443                 mActivityManager.clearApplicationUserData(packageName, observer, 0);
   2444             } catch (RemoteException e) {
   2445                 // can't happen because the activity manager is in this process
   2446             }
   2447 
   2448             // only wait 10 seconds for the clear data to happen
   2449             long timeoutMark = System.currentTimeMillis() + TIMEOUT_INTERVAL;
   2450             while (mClearingData && (System.currentTimeMillis() < timeoutMark)) {
   2451                 try {
   2452                     mClearDataLock.wait(5000);
   2453                 } catch (InterruptedException e) {
   2454                     // won't happen, but still.
   2455                     mClearingData = false;
   2456                 }
   2457             }
   2458         }
   2459     }
   2460 
   2461     class ClearDataObserver extends IPackageDataObserver.Stub {
   2462         public void onRemoveCompleted(String packageName, boolean succeeded) {
   2463             synchronized(mClearDataLock) {
   2464                 mClearingData = false;
   2465                 mClearDataLock.notifyAll();
   2466             }
   2467         }
   2468     }
   2469 
   2470     // Get the restore-set token for the best-available restore set for this package:
   2471     // the active set if possible, else the ancestral one.  Returns zero if none available.
   2472     public long getAvailableRestoreToken(String packageName) {
   2473         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   2474                 "getAvailableRestoreToken");
   2475 
   2476         long token = mAncestralToken;
   2477         synchronized (mQueueLock) {
   2478             if (mEverStoredApps.contains(packageName)) {
   2479                 if (MORE_DEBUG) {
   2480                     Slog.i(TAG, "App in ever-stored, so using current token");
   2481                 }
   2482                 token = mCurrentToken;
   2483             }
   2484         }
   2485         if (MORE_DEBUG) Slog.i(TAG, "getAvailableRestoreToken() == " + token);
   2486         return token;
   2487     }
   2488 
   2489     public int requestBackup(String[] packages, IBackupObserver observer) {
   2490         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "requestBackup");
   2491 
   2492         if (packages == null || packages.length < 1) {
   2493             Slog.e(TAG, "No packages named for backup request");
   2494             sendBackupFinished(observer, BackupManager.ERROR_TRANSPORT_ABORTED);
   2495             throw new IllegalArgumentException("No packages are provided for backup");
   2496         }
   2497 
   2498         IBackupTransport transport = getTransport(mCurrentTransport);
   2499         if (transport == null) {
   2500             sendBackupFinished(observer, BackupManager.ERROR_TRANSPORT_ABORTED);
   2501             return BackupManager.ERROR_TRANSPORT_ABORTED;
   2502         }
   2503 
   2504         ArrayList<String> fullBackupList = new ArrayList<>();
   2505         ArrayList<String> kvBackupList = new ArrayList<>();
   2506         for (String packageName : packages) {
   2507             try {
   2508                 PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName,
   2509                         PackageManager.GET_SIGNATURES);
   2510                 if (!appIsEligibleForBackup(packageInfo.applicationInfo)) {
   2511                     sendBackupOnPackageResult(observer, packageName,
   2512                             BackupManager.ERROR_BACKUP_NOT_ALLOWED);
   2513                     continue;
   2514                 }
   2515                 if (appGetsFullBackup(packageInfo)) {
   2516                     fullBackupList.add(packageInfo.packageName);
   2517                 } else {
   2518                     kvBackupList.add(packageInfo.packageName);
   2519                 }
   2520             } catch (NameNotFoundException e) {
   2521                 sendBackupOnPackageResult(observer, packageName,
   2522                         BackupManager.ERROR_PACKAGE_NOT_FOUND);
   2523             }
   2524         }
   2525         EventLog.writeEvent(EventLogTags.BACKUP_REQUESTED, packages.length, kvBackupList.size(),
   2526                 fullBackupList.size());
   2527         if (MORE_DEBUG) {
   2528             Slog.i(TAG, "Backup requested for " + packages.length + " packages, of them: " +
   2529                 fullBackupList.size() + " full backups, " + kvBackupList.size() + " k/v backups");
   2530         }
   2531 
   2532         String dirName;
   2533         try {
   2534             dirName = transport.transportDirName();
   2535         } catch (Exception e) {
   2536             Slog.e(TAG, "Transport unavailable while attempting backup: " + e.getMessage());
   2537             sendBackupFinished(observer, BackupManager.ERROR_TRANSPORT_ABORTED);
   2538             return BackupManager.ERROR_TRANSPORT_ABORTED;
   2539         }
   2540         Message msg = mBackupHandler.obtainMessage(MSG_REQUEST_BACKUP);
   2541         msg.obj = new BackupParams(transport, dirName, kvBackupList, fullBackupList, observer,
   2542                 true);
   2543         mBackupHandler.sendMessage(msg);
   2544         return BackupManager.SUCCESS;
   2545     }
   2546 
   2547     // -----
   2548     // Interface and methods used by the asynchronous-with-timeout backup/restore operations
   2549 
   2550     interface BackupRestoreTask {
   2551         // Execute one tick of whatever state machine the task implements
   2552         void execute();
   2553 
   2554         // An operation that wanted a callback has completed
   2555         void operationComplete(long result);
   2556 
   2557         // An operation that wanted a callback has timed out
   2558         void handleTimeout();
   2559     }
   2560 
   2561     void prepareOperationTimeout(int token, long interval, BackupRestoreTask callback) {
   2562         if (MORE_DEBUG) Slog.v(TAG, "starting timeout: token=" + Integer.toHexString(token)
   2563                 + " interval=" + interval + " callback=" + callback);
   2564         synchronized (mCurrentOpLock) {
   2565             mCurrentOperations.put(token, new Operation(OP_PENDING, callback));
   2566 
   2567             Message msg = mBackupHandler.obtainMessage(MSG_TIMEOUT, token, 0, callback);
   2568             mBackupHandler.sendMessageDelayed(msg, interval);
   2569         }
   2570     }
   2571 
   2572     // synchronous waiter case
   2573     boolean waitUntilOperationComplete(int token) {
   2574         if (MORE_DEBUG) Slog.i(TAG, "Blocking until operation complete for "
   2575                 + Integer.toHexString(token));
   2576         int finalState = OP_PENDING;
   2577         Operation op = null;
   2578         synchronized (mCurrentOpLock) {
   2579             while (true) {
   2580                 op = mCurrentOperations.get(token);
   2581                 if (op == null) {
   2582                     // mysterious disappearance: treat as success with no callback
   2583                     break;
   2584                 } else {
   2585                     if (op.state == OP_PENDING) {
   2586                         try {
   2587                             mCurrentOpLock.wait();
   2588                         } catch (InterruptedException e) {}
   2589                         // When the wait is notified we loop around and recheck the current state
   2590                     } else {
   2591                         // No longer pending; we're done
   2592                         finalState = op.state;
   2593                         break;
   2594                     }
   2595                 }
   2596             }
   2597         }
   2598 
   2599         mBackupHandler.removeMessages(MSG_TIMEOUT);
   2600         if (MORE_DEBUG) Slog.v(TAG, "operation " + Integer.toHexString(token)
   2601                 + " complete: finalState=" + finalState);
   2602         return finalState == OP_ACKNOWLEDGED;
   2603     }
   2604 
   2605     void handleTimeout(int token, Object obj) {
   2606         // Notify any synchronous waiters
   2607         Operation op = null;
   2608         synchronized (mCurrentOpLock) {
   2609             op = mCurrentOperations.get(token);
   2610             if (MORE_DEBUG) {
   2611                 if (op == null) Slog.w(TAG, "Timeout of token " + Integer.toHexString(token)
   2612                         + " but no op found");
   2613             }
   2614             int state = (op != null) ? op.state : OP_TIMEOUT;
   2615             if (state == OP_ACKNOWLEDGED) {
   2616                 // The operation finished cleanly, so we have nothing more to do.
   2617                 if (MORE_DEBUG) {
   2618                     Slog.v(TAG, "handleTimeout() after success; cleanup happens now");
   2619                 }
   2620                 op = null;
   2621                 mCurrentOperations.delete(token);
   2622             } else if (state == OP_PENDING) {
   2623                 if (DEBUG) Slog.v(TAG, "TIMEOUT: token=" + Integer.toHexString(token));
   2624                 op.state = OP_TIMEOUT;
   2625                 // Leaves the object in place for later ack
   2626             }
   2627             mCurrentOpLock.notifyAll();
   2628         }
   2629 
   2630         // If there's a TimeoutHandler for this event, call it
   2631         if (op != null && op.callback != null) {
   2632             if (MORE_DEBUG) {
   2633                 Slog.v(TAG, "   Invoking timeout on " + op.callback);
   2634             }
   2635             op.callback.handleTimeout();
   2636         }
   2637     }
   2638 
   2639     // ----- Back up a set of applications via a worker thread -----
   2640 
   2641     enum BackupState {
   2642         INITIAL,
   2643         RUNNING_QUEUE,
   2644         FINAL
   2645     }
   2646 
   2647     class PerformBackupTask implements BackupRestoreTask {
   2648         private static final String TAG = "PerformBackupTask";
   2649 
   2650         IBackupTransport mTransport;
   2651         ArrayList<BackupRequest> mQueue;
   2652         ArrayList<BackupRequest> mOriginalQueue;
   2653         File mStateDir;
   2654         File mJournal;
   2655         BackupState mCurrentState;
   2656         ArrayList<String> mPendingFullBackups;
   2657         IBackupObserver mObserver;
   2658 
   2659         // carried information about the current in-flight operation
   2660         IBackupAgent mAgentBinder;
   2661         PackageInfo mCurrentPackage;
   2662         File mSavedStateName;
   2663         File mBackupDataName;
   2664         File mNewStateName;
   2665         ParcelFileDescriptor mSavedState;
   2666         ParcelFileDescriptor mBackupData;
   2667         ParcelFileDescriptor mNewState;
   2668         int mStatus;
   2669         boolean mFinished;
   2670         boolean mUserInitiated;
   2671 
   2672         public PerformBackupTask(IBackupTransport transport, String dirName,
   2673                 ArrayList<BackupRequest> queue, File journal, IBackupObserver observer,
   2674                 ArrayList<String> pendingFullBackups, boolean userInitiated) {
   2675             mTransport = transport;
   2676             mOriginalQueue = queue;
   2677             mJournal = journal;
   2678             mObserver = observer;
   2679             mPendingFullBackups = pendingFullBackups;
   2680             mUserInitiated = userInitiated;
   2681 
   2682             mStateDir = new File(mBaseStateDir, dirName);
   2683 
   2684             mCurrentState = BackupState.INITIAL;
   2685             mFinished = false;
   2686 
   2687             addBackupTrace("STATE => INITIAL");
   2688         }
   2689 
   2690         // Main entry point: perform one chunk of work, updating the state as appropriate
   2691         // and reposting the next chunk to the primary backup handler thread.
   2692         @Override
   2693         public void execute() {
   2694             switch (mCurrentState) {
   2695                 case INITIAL:
   2696                     beginBackup();
   2697                     break;
   2698 
   2699                 case RUNNING_QUEUE:
   2700                     invokeNextAgent();
   2701                     break;
   2702 
   2703                 case FINAL:
   2704                     if (!mFinished) finalizeBackup();
   2705                     else {
   2706                         Slog.e(TAG, "Duplicate finish");
   2707                     }
   2708                     mFinished = true;
   2709                     break;
   2710             }
   2711         }
   2712 
   2713         // We're starting a backup pass.  Initialize the transport and send
   2714         // the PM metadata blob if we haven't already.
   2715         void beginBackup() {
   2716             if (DEBUG_BACKUP_TRACE) {
   2717                 clearBackupTrace();
   2718                 StringBuilder b = new StringBuilder(256);
   2719                 b.append("beginBackup: [");
   2720                 for (BackupRequest req : mOriginalQueue) {
   2721                     b.append(' ');
   2722                     b.append(req.packageName);
   2723                 }
   2724                 b.append(" ]");
   2725                 addBackupTrace(b.toString());
   2726             }
   2727 
   2728             mAgentBinder = null;
   2729             mStatus = BackupTransport.TRANSPORT_OK;
   2730 
   2731             // Sanity check: if the queue is empty we have no work to do.
   2732             if (mOriginalQueue.isEmpty() && mPendingFullBackups.isEmpty()) {
   2733                 Slog.w(TAG, "Backup begun with an empty queue - nothing to do.");
   2734                 addBackupTrace("queue empty at begin");
   2735                 sendBackupFinished(mObserver, BackupManager.SUCCESS);
   2736                 executeNextState(BackupState.FINAL);
   2737                 return;
   2738             }
   2739 
   2740             // We need to retain the original queue contents in case of transport
   2741             // failure, but we want a working copy that we can manipulate along
   2742             // the way.
   2743             mQueue = (ArrayList<BackupRequest>) mOriginalQueue.clone();
   2744 
   2745             // The app metadata pseudopackage might also be represented in the
   2746             // backup queue if apps have been added/removed since the last time
   2747             // we performed a backup.  Drop it from the working queue now that
   2748             // we're committed to evaluating it for backup regardless.
   2749             for (int i = 0; i < mQueue.size(); i++) {
   2750                 if (PACKAGE_MANAGER_SENTINEL.equals(mQueue.get(i).packageName)) {
   2751                     if (MORE_DEBUG) {
   2752                         Slog.i(TAG, "Metadata in queue; eliding");
   2753                     }
   2754                     mQueue.remove(i);
   2755                     break;
   2756                 }
   2757             }
   2758 
   2759             if (DEBUG) Slog.v(TAG, "Beginning backup of " + mQueue.size() + " targets");
   2760 
   2761             File pmState = new File(mStateDir, PACKAGE_MANAGER_SENTINEL);
   2762             try {
   2763                 final String transportName = mTransport.transportDirName();
   2764                 EventLog.writeEvent(EventLogTags.BACKUP_START, transportName);
   2765 
   2766                 // If we haven't stored package manager metadata yet, we must init the transport.
   2767                 if (mStatus == BackupTransport.TRANSPORT_OK && pmState.length() <= 0) {
   2768                     Slog.i(TAG, "Initializing (wiping) backup state and transport storage");
   2769                     addBackupTrace("initializing transport " + transportName);
   2770                     resetBackupState(mStateDir);  // Just to make sure.
   2771                     mStatus = mTransport.initializeDevice();
   2772 
   2773                     addBackupTrace("transport.initializeDevice() == " + mStatus);
   2774                     if (mStatus == BackupTransport.TRANSPORT_OK) {
   2775                         EventLog.writeEvent(EventLogTags.BACKUP_INITIALIZE);
   2776                     } else {
   2777                         EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, "(initialize)");
   2778                         Slog.e(TAG, "Transport error in initializeDevice()");
   2779                     }
   2780                 }
   2781 
   2782                 // The package manager doesn't have a proper <application> etc, but since
   2783                 // it's running here in the system process we can just set up its agent
   2784                 // directly and use a synthetic BackupRequest.  We always run this pass
   2785                 // because it's cheap and this way we guarantee that we don't get out of
   2786                 // step even if we're selecting among various transports at run time.
   2787                 if (mStatus == BackupTransport.TRANSPORT_OK) {
   2788                     PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
   2789                             mPackageManager);
   2790                     mStatus = invokeAgentForBackup(PACKAGE_MANAGER_SENTINEL,
   2791                             IBackupAgent.Stub.asInterface(pmAgent.onBind()), mTransport);
   2792                     addBackupTrace("PMBA invoke: " + mStatus);
   2793 
   2794                     // Because the PMBA is a local instance, it has already executed its
   2795                     // backup callback and returned.  Blow away the lingering (spurious)
   2796                     // pending timeout message for it.
   2797                     mBackupHandler.removeMessages(MSG_TIMEOUT);
   2798                 }
   2799 
   2800                 if (mStatus == BackupTransport.TRANSPORT_NOT_INITIALIZED) {
   2801                     // The backend reports that our dataset has been wiped.  Note this in
   2802                     // the event log; the no-success code below will reset the backup
   2803                     // state as well.
   2804                     EventLog.writeEvent(EventLogTags.BACKUP_RESET, mTransport.transportDirName());
   2805                 }
   2806             } catch (Exception e) {
   2807                 Slog.e(TAG, "Error in backup thread", e);
   2808                 addBackupTrace("Exception in backup thread: " + e);
   2809                 mStatus = BackupTransport.TRANSPORT_ERROR;
   2810             } finally {
   2811                 // If we've succeeded so far, invokeAgentForBackup() will have run the PM
   2812                 // metadata and its completion/timeout callback will continue the state
   2813                 // machine chain.  If it failed that won't happen; we handle that now.
   2814                 addBackupTrace("exiting prelim: " + mStatus);
   2815                 if (mStatus != BackupTransport.TRANSPORT_OK) {
   2816                     // if things went wrong at this point, we need to
   2817                     // restage everything and try again later.
   2818                     resetBackupState(mStateDir);  // Just to make sure.
   2819                     // In case of any other error, it's backup transport error.
   2820                     sendBackupFinished(mObserver, BackupManager.ERROR_TRANSPORT_ABORTED);
   2821                     executeNextState(BackupState.FINAL);
   2822                 }
   2823             }
   2824         }
   2825 
   2826         // Transport has been initialized and the PM metadata submitted successfully
   2827         // if that was warranted.  Now we process the single next thing in the queue.
   2828         void invokeNextAgent() {
   2829             mStatus = BackupTransport.TRANSPORT_OK;
   2830             addBackupTrace("invoke q=" + mQueue.size());
   2831 
   2832             // Sanity check that we have work to do.  If not, skip to the end where
   2833             // we reestablish the wakelock invariants etc.
   2834             if (mQueue.isEmpty()) {
   2835                 if (MORE_DEBUG) Slog.i(TAG, "queue now empty");
   2836                 executeNextState(BackupState.FINAL);
   2837                 return;
   2838             }
   2839 
   2840             // pop the entry we're going to process on this step
   2841             BackupRequest request = mQueue.get(0);
   2842             mQueue.remove(0);
   2843 
   2844             Slog.d(TAG, "starting key/value backup of " + request);
   2845             addBackupTrace("launch agent for " + request.packageName);
   2846 
   2847             // Verify that the requested app exists; it might be something that
   2848             // requested a backup but was then uninstalled.  The request was
   2849             // journalled and rather than tamper with the journal it's safer
   2850             // to sanity-check here.  This also gives us the classname of the
   2851             // package's backup agent.
   2852             try {
   2853                 mCurrentPackage = mPackageManager.getPackageInfo(request.packageName,
   2854                         PackageManager.GET_SIGNATURES);
   2855                 if (!appIsEligibleForBackup(mCurrentPackage.applicationInfo)) {
   2856                     // The manifest has changed but we had a stale backup request pending.
   2857                     // This won't happen again because the app won't be requesting further
   2858                     // backups.
   2859                     Slog.i(TAG, "Package " + request.packageName
   2860                             + " no longer supports backup; skipping");
   2861                     addBackupTrace("skipping - not eligible, completion is noop");
   2862                     // Shouldn't happen in case of requested backup, as pre-check was done in
   2863                     // #requestBackup(), except to app update done concurrently
   2864                     sendBackupOnPackageResult(mObserver, mCurrentPackage.packageName,
   2865                             BackupManager.ERROR_BACKUP_NOT_ALLOWED);
   2866                     executeNextState(BackupState.RUNNING_QUEUE);
   2867                     return;
   2868                 }
   2869 
   2870                 if (appGetsFullBackup(mCurrentPackage)) {
   2871                     // It's possible that this app *formerly* was enqueued for key/value backup,
   2872                     // but has since been updated and now only supports the full-data path.
   2873                     // Don't proceed with a key/value backup for it in this case.
   2874                     Slog.i(TAG, "Package " + request.packageName
   2875                             + " requests full-data rather than key/value; skipping");
   2876                     addBackupTrace("skipping - fullBackupOnly, completion is noop");
   2877                     // Shouldn't happen in case of requested backup, as pre-check was done in
   2878                     // #requestBackup()
   2879                     sendBackupOnPackageResult(mObserver, mCurrentPackage.packageName,
   2880                             BackupManager.ERROR_BACKUP_NOT_ALLOWED);
   2881                     executeNextState(BackupState.RUNNING_QUEUE);
   2882                     return;
   2883                 }
   2884 
   2885                 if (appIsStopped(mCurrentPackage.applicationInfo)) {
   2886                     // The app has been force-stopped or cleared or just installed,
   2887                     // and not yet launched out of that state, so just as it won't
   2888                     // receive broadcasts, we won't run it for backup.
   2889                     addBackupTrace("skipping - stopped");
   2890                     sendBackupOnPackageResult(mObserver, mCurrentPackage.packageName,
   2891                             BackupManager.ERROR_BACKUP_NOT_ALLOWED);
   2892                     executeNextState(BackupState.RUNNING_QUEUE);
   2893                     return;
   2894                 }
   2895 
   2896                 IBackupAgent agent = null;
   2897                 try {
   2898                     mWakelock.setWorkSource(new WorkSource(mCurrentPackage.applicationInfo.uid));
   2899                     agent = bindToAgentSynchronous(mCurrentPackage.applicationInfo,
   2900                             IApplicationThread.BACKUP_MODE_INCREMENTAL);
   2901                     addBackupTrace("agent bound; a? = " + (agent != null));
   2902                     if (agent != null) {
   2903                         mAgentBinder = agent;
   2904                         mStatus = invokeAgentForBackup(request.packageName, agent, mTransport);
   2905                         // at this point we'll either get a completion callback from the
   2906                         // agent, or a timeout message on the main handler.  either way, we're
   2907                         // done here as long as we're successful so far.
   2908                     } else {
   2909                         // Timeout waiting for the agent
   2910                         mStatus = BackupTransport.AGENT_ERROR;
   2911                     }
   2912                 } catch (SecurityException ex) {
   2913                     // Try for the next one.
   2914                     Slog.d(TAG, "error in bind/backup", ex);
   2915                     mStatus = BackupTransport.AGENT_ERROR;
   2916                             addBackupTrace("agent SE");
   2917                 }
   2918             } catch (NameNotFoundException e) {
   2919                 Slog.d(TAG, "Package does not exist; skipping");
   2920                 addBackupTrace("no such package");
   2921                 mStatus = BackupTransport.AGENT_UNKNOWN;
   2922             } finally {
   2923                 mWakelock.setWorkSource(null);
   2924 
   2925                 // If there was an agent error, no timeout/completion handling will occur.
   2926                 // That means we need to direct to the next state ourselves.
   2927                 if (mStatus != BackupTransport.TRANSPORT_OK) {
   2928                     BackupState nextState = BackupState.RUNNING_QUEUE;
   2929                     mAgentBinder = null;
   2930 
   2931                     // An agent-level failure means we reenqueue this one agent for
   2932                     // a later retry, but otherwise proceed normally.
   2933                     if (mStatus == BackupTransport.AGENT_ERROR) {
   2934                         if (MORE_DEBUG) Slog.i(TAG, "Agent failure for " + request.packageName
   2935                                 + " - restaging");
   2936                         dataChangedImpl(request.packageName);
   2937                         mStatus = BackupTransport.TRANSPORT_OK;
   2938                         if (mQueue.isEmpty()) nextState = BackupState.FINAL;
   2939                         sendBackupOnPackageResult(mObserver, mCurrentPackage.packageName,
   2940                                 BackupManager.ERROR_AGENT_FAILURE);
   2941                     } else if (mStatus == BackupTransport.AGENT_UNKNOWN) {
   2942                         // Failed lookup of the app, so we couldn't bring up an agent, but
   2943                         // we're otherwise fine.  Just drop it and go on to the next as usual.
   2944                         mStatus = BackupTransport.TRANSPORT_OK;
   2945                         sendBackupOnPackageResult(mObserver, mCurrentPackage.packageName,
   2946                                 BackupManager.ERROR_PACKAGE_NOT_FOUND);
   2947                     } else {
   2948                         // Transport-level failure means we reenqueue everything
   2949                         revertAndEndBackup();
   2950                         nextState = BackupState.FINAL;
   2951                     }
   2952 
   2953                     executeNextState(nextState);
   2954                 } else {
   2955                     // success case
   2956                     addBackupTrace("expecting completion/timeout callback");
   2957                 }
   2958             }
   2959         }
   2960 
   2961         void finalizeBackup() {
   2962             addBackupTrace("finishing");
   2963 
   2964             // Either backup was successful, in which case we of course do not need
   2965             // this pass's journal any more; or it failed, in which case we just
   2966             // re-enqueued all of these packages in the current active journal.
   2967             // Either way, we no longer need this pass's journal.
   2968             if (mJournal != null && !mJournal.delete()) {
   2969                 Slog.e(TAG, "Unable to remove backup journal file " + mJournal);
   2970             }
   2971 
   2972             // If everything actually went through and this is the first time we've
   2973             // done a backup, we can now record what the current backup dataset token
   2974             // is.
   2975             if ((mCurrentToken == 0) && (mStatus == BackupTransport.TRANSPORT_OK)) {
   2976                 addBackupTrace("success; recording token");
   2977                 try {
   2978                     mCurrentToken = mTransport.getCurrentRestoreSet();
   2979                     writeRestoreTokens();
   2980                 } catch (Exception e) {
   2981                     // nothing for it at this point, unfortunately, but this will be
   2982                     // recorded the next time we fully succeed.
   2983                     Slog.e(TAG, "Transport threw reporting restore set: " + e.getMessage());
   2984                     addBackupTrace("transport threw returning token");
   2985                 }
   2986             }
   2987 
   2988             // Set up the next backup pass - at this point we can set mBackupRunning
   2989             // to false to allow another pass to fire, because we're done with the
   2990             // state machine sequence and the wakelock is refcounted.
   2991             synchronized (mQueueLock) {
   2992                 mBackupRunning = false;
   2993                 if (mStatus == BackupTransport.TRANSPORT_NOT_INITIALIZED) {
   2994                     // Make sure we back up everything and perform the one-time init
   2995                     if (MORE_DEBUG) Slog.d(TAG, "Server requires init; rerunning");
   2996                     addBackupTrace("init required; rerunning");
   2997                     try {
   2998                         final String name = getTransportName(mTransport);
   2999                         if (name != null) {
   3000                             mPendingInits.add(name);
   3001                         } else {
   3002                             if (DEBUG) {
   3003                                 Slog.w(TAG, "Couldn't find name of transport " + mTransport
   3004                                         + " for init");
   3005                             }
   3006                         }
   3007                     } catch (Exception e) {
   3008                         Slog.w(TAG, "Failed to query transport name for init: " + e.getMessage());
   3009                         // swallow it and proceed; we don't rely on this
   3010                     }
   3011                     clearMetadata();
   3012                     backupNow();
   3013                 }
   3014             }
   3015 
   3016             clearBackupTrace();
   3017 
   3018             if (mStatus == BackupTransport.TRANSPORT_OK &&
   3019                     mPendingFullBackups != null && !mPendingFullBackups.isEmpty()) {
   3020                 Slog.d(TAG, "Starting full backups for: " + mPendingFullBackups);
   3021                 CountDownLatch latch = new CountDownLatch(1);
   3022                 String[] fullBackups =
   3023                         mPendingFullBackups.toArray(new String[mPendingFullBackups.size()]);
   3024                 PerformFullTransportBackupTask task =
   3025                         new PerformFullTransportBackupTask(/*fullBackupRestoreObserver*/ null,
   3026                                 fullBackups, /*updateSchedule*/ false, /*runningJob*/ null, latch,
   3027                                 mObserver, mUserInitiated);
   3028                 // Acquiring wakelock for PerformFullTransportBackupTask before its start.
   3029                 mWakelock.acquire();
   3030                 (new Thread(task, "full-transport-requested")).start();
   3031             } else {
   3032                 switch (mStatus) {
   3033                     case BackupTransport.TRANSPORT_OK:
   3034                         sendBackupFinished(mObserver, BackupManager.SUCCESS);
   3035                         break;
   3036                     case BackupTransport.TRANSPORT_NOT_INITIALIZED:
   3037                         sendBackupFinished(mObserver, BackupManager.ERROR_TRANSPORT_ABORTED);
   3038                         break;
   3039                     case BackupTransport.TRANSPORT_ERROR:
   3040                     default:
   3041                         sendBackupFinished(mObserver, BackupManager.ERROR_TRANSPORT_ABORTED);
   3042                         break;
   3043                 }
   3044             }
   3045             Slog.i(BackupManagerService.TAG, "K/V backup pass finished.");
   3046             // Only once we're entirely finished do we release the wakelock for k/v backup.
   3047             mWakelock.release();
   3048         }
   3049 
   3050         // Remove the PM metadata state. This will generate an init on the next pass.
   3051         void clearMetadata() {
   3052             final File pmState = new File(mStateDir, PACKAGE_MANAGER_SENTINEL);
   3053             if (pmState.exists()) pmState.delete();
   3054         }
   3055 
   3056         // Invoke an agent's doBackup() and start a timeout message spinning on the main
   3057         // handler in case it doesn't get back to us.
   3058         int invokeAgentForBackup(String packageName, IBackupAgent agent,
   3059                 IBackupTransport transport) {
   3060             if (DEBUG) Slog.d(TAG, "invokeAgentForBackup on " + packageName);
   3061             addBackupTrace("invoking " + packageName);
   3062 
   3063             mSavedStateName = new File(mStateDir, packageName);
   3064             mBackupDataName = new File(mDataDir, packageName + ".data");
   3065             mNewStateName = new File(mStateDir, packageName + ".new");
   3066             if (MORE_DEBUG) Slog.d(TAG, "data file: " + mBackupDataName);
   3067 
   3068             mSavedState = null;
   3069             mBackupData = null;
   3070             mNewState = null;
   3071 
   3072             final int token = generateToken();
   3073             try {
   3074                 // Look up the package info & signatures.  This is first so that if it
   3075                 // throws an exception, there's no file setup yet that would need to
   3076                 // be unraveled.
   3077                 if (packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
   3078                     // The metadata 'package' is synthetic; construct one and make
   3079                     // sure our global state is pointed at it
   3080                     mCurrentPackage = new PackageInfo();
   3081                     mCurrentPackage.packageName = packageName;
   3082                 }
   3083 
   3084                 // In a full backup, we pass a null ParcelFileDescriptor as
   3085                 // the saved-state "file". This is by definition an incremental,
   3086                 // so we build a saved state file to pass.
   3087                 mSavedState = ParcelFileDescriptor.open(mSavedStateName,
   3088                         ParcelFileDescriptor.MODE_READ_ONLY |
   3089                         ParcelFileDescriptor.MODE_CREATE);  // Make an empty file if necessary
   3090 
   3091                 mBackupData = ParcelFileDescriptor.open(mBackupDataName,
   3092                         ParcelFileDescriptor.MODE_READ_WRITE |
   3093                         ParcelFileDescriptor.MODE_CREATE |
   3094                         ParcelFileDescriptor.MODE_TRUNCATE);
   3095 
   3096                 if (!SELinux.restorecon(mBackupDataName)) {
   3097                     Slog.e(TAG, "SELinux restorecon failed on " + mBackupDataName);
   3098                 }
   3099 
   3100                 mNewState = ParcelFileDescriptor.open(mNewStateName,
   3101                         ParcelFileDescriptor.MODE_READ_WRITE |
   3102                         ParcelFileDescriptor.MODE_CREATE |
   3103                         ParcelFileDescriptor.MODE_TRUNCATE);
   3104 
   3105                 // Initiate the target's backup pass
   3106                 addBackupTrace("setting timeout");
   3107                 prepareOperationTimeout(token, TIMEOUT_BACKUP_INTERVAL, this);
   3108                 addBackupTrace("calling agent doBackup()");
   3109                 agent.doBackup(mSavedState, mBackupData, mNewState, token, mBackupManagerBinder);
   3110             } catch (Exception e) {
   3111                 Slog.e(TAG, "Error invoking for backup on " + packageName);
   3112                 addBackupTrace("exception: " + e);
   3113                 EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName,
   3114                         e.toString());
   3115                 agentErrorCleanup();
   3116                 return BackupTransport.AGENT_ERROR;
   3117             }
   3118 
   3119             // At this point the agent is off and running.  The next thing to happen will
   3120             // either be a callback from the agent, at which point we'll process its data
   3121             // for transport, or a timeout.  Either way the next phase will happen in
   3122             // response to the TimeoutHandler interface callbacks.
   3123             addBackupTrace("invoke success");
   3124             return BackupTransport.TRANSPORT_OK;
   3125         }
   3126 
   3127         public void failAgent(IBackupAgent agent, String message) {
   3128             try {
   3129                 agent.fail(message);
   3130             } catch (Exception e) {
   3131                 Slog.w(TAG, "Error conveying failure to " + mCurrentPackage.packageName);
   3132             }
   3133         }
   3134 
   3135         // SHA-1 a byte array and return the result in hex
   3136         private String SHA1Checksum(byte[] input) {
   3137             final byte[] checksum;
   3138             try {
   3139                 MessageDigest md = MessageDigest.getInstance("SHA-1");
   3140                 checksum = md.digest(input);
   3141             } catch (NoSuchAlgorithmException e) {
   3142                 Slog.e(TAG, "Unable to use SHA-1!");
   3143                 return "00";
   3144             }
   3145 
   3146             StringBuffer sb = new StringBuffer(checksum.length * 2);
   3147             for (int i = 0; i < checksum.length; i++) {
   3148                 sb.append(Integer.toHexString(checksum[i]));
   3149             }
   3150             return sb.toString();
   3151         }
   3152 
   3153         private void writeWidgetPayloadIfAppropriate(FileDescriptor fd, String pkgName)
   3154                 throws IOException {
   3155             // TODO: http://b/22388012
   3156             byte[] widgetState = AppWidgetBackupBridge.getWidgetState(pkgName,
   3157                     UserHandle.USER_SYSTEM);
   3158             // has the widget state changed since last time?
   3159             final File widgetFile = new File(mStateDir, pkgName + "_widget");
   3160             final boolean priorStateExists = widgetFile.exists();
   3161 
   3162             if (MORE_DEBUG) {
   3163                 if (priorStateExists || widgetState != null) {
   3164                     Slog.i(TAG, "Checking widget update: state=" + (widgetState != null)
   3165                             + " prior=" + priorStateExists);
   3166                 }
   3167             }
   3168 
   3169             if (!priorStateExists && widgetState == null) {
   3170                 // no prior state, no new state => nothing to do
   3171                 return;
   3172             }
   3173 
   3174             // if the new state is not null, we might need to compare checksums to
   3175             // determine whether to update the widget blob in the archive.  If the
   3176             // widget state *is* null, we know a priori at this point that we simply
   3177             // need to commit a deletion for it.
   3178             String newChecksum = null;
   3179             if (widgetState != null) {
   3180                 newChecksum = SHA1Checksum(widgetState);
   3181                 if (priorStateExists) {
   3182                     final String priorChecksum;
   3183                     try (
   3184                         FileInputStream fin = new FileInputStream(widgetFile);
   3185                         DataInputStream in = new DataInputStream(fin)
   3186                     ) {
   3187                         priorChecksum = in.readUTF();
   3188                     }
   3189                     if (Objects.equals(newChecksum, priorChecksum)) {
   3190                         // Same checksum => no state change => don't rewrite the widget data
   3191                         return;
   3192                     }
   3193                 }
   3194             } // else widget state *became* empty, so we need to commit a deletion
   3195 
   3196             BackupDataOutput out = new BackupDataOutput(fd);
   3197             if (widgetState != null) {
   3198                 try (
   3199                     FileOutputStream fout = new FileOutputStream(widgetFile);
   3200                     DataOutputStream stateOut = new DataOutputStream(fout)
   3201                 ) {
   3202                     stateOut.writeUTF(newChecksum);
   3203                 }
   3204 
   3205                 out.writeEntityHeader(KEY_WIDGET_STATE, widgetState.length);
   3206                 out.writeEntityData(widgetState, widgetState.length);
   3207             } else {
   3208                 // Widget state for this app has been removed; commit a deletion
   3209                 out.writeEntityHeader(KEY_WIDGET_STATE, -1);
   3210                 widgetFile.delete();
   3211             }
   3212         }
   3213 
   3214         @Override
   3215         public void operationComplete(long unusedResult) {
   3216             // The agent reported back to us!
   3217 
   3218             if (mBackupData == null) {
   3219                 // This callback was racing with our timeout, so we've cleaned up the
   3220                 // agent state already and are on to the next thing.  We have nothing
   3221                 // further to do here: agent state having been cleared means that we've
   3222                 // initiated the appropriate next operation.
   3223                 final String pkg = (mCurrentPackage != null)
   3224                         ? mCurrentPackage.packageName : "[none]";
   3225                 if (MORE_DEBUG) {
   3226                     Slog.i(TAG, "Callback after agent teardown: " + pkg);
   3227                 }
   3228                 addBackupTrace("late opComplete; curPkg = " + pkg);
   3229                 return;
   3230             }
   3231 
   3232             final String pkgName = mCurrentPackage.packageName;
   3233             final long filepos = mBackupDataName.length();
   3234             FileDescriptor fd = mBackupData.getFileDescriptor();
   3235             try {
   3236                 // If it's a 3rd party app, see whether they wrote any protected keys
   3237                 // and complain mightily if they are attempting shenanigans.
   3238                 if (mCurrentPackage.applicationInfo != null &&
   3239                         (mCurrentPackage.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
   3240                     ParcelFileDescriptor readFd = ParcelFileDescriptor.open(mBackupDataName,
   3241                             ParcelFileDescriptor.MODE_READ_ONLY);
   3242                     BackupDataInput in = new BackupDataInput(readFd.getFileDescriptor());
   3243                     try {
   3244                         while (in.readNextHeader()) {
   3245                             final String key = in.getKey();
   3246                             if (key != null && key.charAt(0) >= 0xff00) {
   3247                                 // Not okay: crash them and bail.
   3248                                 failAgent(mAgentBinder, "Illegal backup key: " + key);
   3249                                 addBackupTrace("illegal key " + key + " from " + pkgName);
   3250                                 EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, pkgName,
   3251                                         "bad key");
   3252                                 mBackupHandler.removeMessages(MSG_TIMEOUT);
   3253                                 sendBackupOnPackageResult(mObserver, pkgName,
   3254                                         BackupManager.ERROR_AGENT_FAILURE);
   3255                                 agentErrorCleanup();
   3256                                 // agentErrorCleanup() implicitly executes next state properly
   3257                                 return;
   3258                             }
   3259                             in.skipEntityData();
   3260                         }
   3261                     } finally {
   3262                         if (readFd != null) {
   3263                             readFd.close();
   3264                         }
   3265                     }
   3266                 }
   3267 
   3268                 // Piggyback the widget state payload, if any
   3269                 writeWidgetPayloadIfAppropriate(fd, pkgName);
   3270             } catch (IOException e) {
   3271                 // Hard disk error; recovery/failure policy TBD.  For now roll back,
   3272                 // but we may want to consider this a transport-level failure (i.e.
   3273                 // we're in such a bad state that we can't contemplate doing backup
   3274                 // operations any more during this pass).
   3275                 Slog.w(TAG, "Unable to save widget state for " + pkgName);
   3276                 try {
   3277                     Os.ftruncate(fd, filepos);
   3278                 } catch (ErrnoException ee) {
   3279                     Slog.w(TAG, "Unable to roll back!");
   3280                 }
   3281             }
   3282 
   3283             // Spin the data off to the transport and proceed with the next stage.
   3284             if (MORE_DEBUG) Slog.v(TAG, "operationComplete(): sending data to transport for "
   3285                     + pkgName);
   3286             mBackupHandler.removeMessages(MSG_TIMEOUT);
   3287             clearAgentState();
   3288             addBackupTrace("operation complete");
   3289 
   3290             ParcelFileDescriptor backupData = null;
   3291             mStatus = BackupTransport.TRANSPORT_OK;
   3292             long size = 0;
   3293             try {
   3294                 size = mBackupDataName.length();
   3295                 if (size > 0) {
   3296                     if (mStatus == BackupTransport.TRANSPORT_OK) {
   3297                         backupData = ParcelFileDescriptor.open(mBackupDataName,
   3298                                 ParcelFileDescriptor.MODE_READ_ONLY);
   3299                         addBackupTrace("sending data to transport");
   3300                         int flags = mUserInitiated ? BackupTransport.FLAG_USER_INITIATED : 0;
   3301                         mStatus = mTransport.performBackup(mCurrentPackage, backupData, flags);
   3302                     }
   3303 
   3304                     // TODO - We call finishBackup() for each application backed up, because
   3305                     // we need to know now whether it succeeded or failed.  Instead, we should
   3306                     // hold off on finishBackup() until the end, which implies holding off on
   3307                     // renaming *all* the output state files (see below) until that happens.
   3308 
   3309                     addBackupTrace("data delivered: " + mStatus);
   3310                     if (mStatus == BackupTransport.TRANSPORT_OK) {
   3311                         addBackupTrace("finishing op on transport");
   3312                         mStatus = mTransport.finishBackup();
   3313                         addBackupTrace("finished: " + mStatus);
   3314                     } else if (mStatus == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
   3315                         addBackupTrace("transport rejected package");
   3316                     }
   3317                 } else {
   3318                     if (MORE_DEBUG) Slog.i(TAG, "no backup data written; not calling transport");
   3319                     addBackupTrace("no data to send");
   3320                 }
   3321 
   3322                 if (mStatus == BackupTransport.TRANSPORT_OK) {
   3323                     // After successful transport, delete the now-stale data
   3324                     // and juggle the files so that next time we supply the agent
   3325                     // with the new state file it just created.
   3326                     mBackupDataName.delete();
   3327                     mNewStateName.renameTo(mSavedStateName);
   3328                     sendBackupOnPackageResult(mObserver, pkgName, BackupManager.SUCCESS);
   3329                     EventLog.writeEvent(EventLogTags.BACKUP_PACKAGE, pkgName, size);
   3330                     logBackupComplete(pkgName);
   3331                 } else if (mStatus == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
   3332                     // The transport has rejected backup of this specific package.  Roll it
   3333                     // back but proceed with running the rest of the queue.
   3334                     mBackupDataName.delete();
   3335                     mNewStateName.delete();
   3336                     sendBackupOnPackageResult(mObserver, pkgName,
   3337                             BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED);
   3338                     EventLogTags.writeBackupAgentFailure(pkgName, "Transport rejected");
   3339                 } else if (mStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
   3340                     sendBackupOnPackageResult(mObserver, pkgName,
   3341                             BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED);
   3342                     EventLog.writeEvent(EventLogTags.BACKUP_QUOTA_EXCEEDED, pkgName);
   3343                 } else {
   3344                     // Actual transport-level failure to communicate the data to the backend
   3345                     sendBackupOnPackageResult(mObserver, pkgName,
   3346                             BackupManager.ERROR_TRANSPORT_ABORTED);
   3347                     EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, pkgName);
   3348                 }
   3349             } catch (Exception e) {
   3350                 sendBackupOnPackageResult(mObserver, pkgName,
   3351                         BackupManager.ERROR_TRANSPORT_ABORTED);
   3352                 Slog.e(TAG, "Transport error backing up " + pkgName, e);
   3353                 EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, pkgName);
   3354                 mStatus = BackupTransport.TRANSPORT_ERROR;
   3355             } finally {
   3356                 try { if (backupData != null) backupData.close(); } catch (IOException e) {}
   3357             }
   3358 
   3359             final BackupState nextState;
   3360             if (mStatus == BackupTransport.TRANSPORT_OK
   3361                     || mStatus == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
   3362                 // Success or single-package rejection.  Proceed with the next app if any,
   3363                 // otherwise we're done.
   3364                 nextState = (mQueue.isEmpty()) ? BackupState.FINAL : BackupState.RUNNING_QUEUE;
   3365             } else if (mStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
   3366                 if (MORE_DEBUG) {
   3367                     Slog.d(TAG, "Package " + mCurrentPackage.packageName +
   3368                             " hit quota limit on k/v backup");
   3369                 }
   3370                 if (mAgentBinder != null) {
   3371                     try {
   3372                         long quota = mTransport.getBackupQuota(mCurrentPackage.packageName, false);
   3373                         mAgentBinder.doQuotaExceeded(size, quota);
   3374                     } catch (Exception e) {
   3375                         Slog.e(TAG, "Unable to notify about quota exceeded: " + e.getMessage());
   3376                     }
   3377                 }
   3378                 nextState = (mQueue.isEmpty()) ? BackupState.FINAL : BackupState.RUNNING_QUEUE;
   3379             } else {
   3380                 // Any other error here indicates a transport-level failure.  That means
   3381                 // we need to halt everything and reschedule everything for next time.
   3382                 revertAndEndBackup();
   3383                 nextState = BackupState.FINAL;
   3384             }
   3385 
   3386             executeNextState(nextState);
   3387         }
   3388 
   3389         @Override
   3390         public void handleTimeout() {
   3391             // Whoops, the current agent timed out running doBackup().  Tidy up and restage
   3392             // it for the next time we run a backup pass.
   3393             // !!! TODO: keep track of failure counts per agent, and blacklist those which
   3394             // fail repeatedly (i.e. have proved themselves to be buggy).
   3395             Slog.e(TAG, "Timeout backing up " + mCurrentPackage.packageName);
   3396             EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, mCurrentPackage.packageName,
   3397                     "timeout");
   3398             addBackupTrace("timeout of " + mCurrentPackage.packageName);
   3399             agentErrorCleanup();
   3400             dataChangedImpl(mCurrentPackage.packageName);
   3401         }
   3402 
   3403         void revertAndEndBackup() {
   3404             if (MORE_DEBUG) Slog.i(TAG, "Reverting backup queue - restaging everything");
   3405             addBackupTrace("transport error; reverting");
   3406 
   3407             // We want to reset the backup schedule based on whatever the transport suggests
   3408             // by way of retry/backoff time.
   3409             long delay;
   3410             try {
   3411                 delay = mTransport.requestBackupTime();
   3412             } catch (Exception e) {
   3413                 Slog.w(TAG, "Unable to contact transport for recommended backoff: " + e.getMessage());
   3414                 delay = 0;  // use the scheduler's default
   3415             }
   3416             KeyValueBackupJob.schedule(mContext, delay);
   3417 
   3418             for (BackupRequest request : mOriginalQueue) {
   3419                 dataChangedImpl(request.packageName);
   3420             }
   3421 
   3422         }
   3423 
   3424         void agentErrorCleanup() {
   3425             mBackupDataName.delete();
   3426             mNewStateName.delete();
   3427             clearAgentState();
   3428 
   3429             executeNextState(mQueue.isEmpty() ? BackupState.FINAL : BackupState.RUNNING_QUEUE);
   3430         }
   3431 
   3432         // Cleanup common to both success and failure cases
   3433         void clearAgentState() {
   3434             try { if (mSavedState != null) mSavedState.close(); } catch (IOException e) {}
   3435             try { if (mBackupData != null) mBackupData.close(); } catch (IOException e) {}
   3436             try { if (mNewState != null) mNewState.close(); } catch (IOException e) {}
   3437             synchronized (mCurrentOpLock) {
   3438                 // Current-operation callback handling requires the validity of these various
   3439                 // bits of internal state as an invariant of the operation still being live.
   3440                 // This means we make sure to clear all of the state in unison inside the lock.
   3441                 mCurrentOperations.clear();
   3442                 mSavedState = mBackupData = mNewState = null;
   3443             }
   3444 
   3445             // If this was a pseudopackage there's no associated Activity Manager state
   3446             if (mCurrentPackage.applicationInfo != null) {
   3447                 addBackupTrace("unbinding " + mCurrentPackage.packageName);
   3448                 try {  // unbind even on timeout, just in case
   3449                     mActivityManager.unbindBackupAgent(mCurrentPackage.applicationInfo);
   3450                 } catch (RemoteException e) { /* can't happen; activity manager is local */ }
   3451             }
   3452         }
   3453 
   3454         void executeNextState(BackupState nextState) {
   3455             if (MORE_DEBUG) Slog.i(TAG, " => executing next step on "
   3456                     + this + " nextState=" + nextState);
   3457             addBackupTrace("executeNextState => " + nextState);
   3458             mCurrentState = nextState;
   3459             Message msg = mBackupHandler.obtainMessage(MSG_BACKUP_RESTORE_STEP, this);
   3460             mBackupHandler.sendMessage(msg);
   3461         }
   3462     }
   3463 
   3464 
   3465     // ----- Full backup/restore to a file/socket -----
   3466 
   3467     class FullBackupObbConnection implements ServiceConnection {
   3468         volatile IObbBackupService mService;
   3469 
   3470         FullBackupObbConnection() {
   3471             mService = null;
   3472         }
   3473 
   3474         public void establish() {
   3475             if (MORE_DEBUG) Slog.i(TAG, "Initiating bind of OBB service on " + this);
   3476             Intent obbIntent = new Intent().setComponent(new ComponentName(
   3477                     "com.android.sharedstoragebackup",
   3478                     "com.android.sharedstoragebackup.ObbBackupService"));
   3479             BackupManagerService.this.mContext.bindServiceAsUser(
   3480                     obbIntent, this, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM);
   3481         }
   3482 
   3483         public void tearDown() {
   3484             BackupManagerService.this.mContext.unbindService(this);
   3485         }
   3486 
   3487         public boolean backupObbs(PackageInfo pkg, OutputStream out) {
   3488             boolean success = false;
   3489             waitForConnection();
   3490 
   3491             ParcelFileDescriptor[] pipes = null;
   3492             try {
   3493                 pipes = ParcelFileDescriptor.createPipe();
   3494                 int token = generateToken();
   3495                 prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL, null);
   3496                 mService.backupObbs(pkg.packageName, pipes[1], token, mBackupManagerBinder);
   3497                 routeSocketDataToOutput(pipes[0], out);
   3498                 success = waitUntilOperationComplete(token);
   3499             } catch (Exception e) {
   3500                 Slog.w(TAG, "Unable to back up OBBs for " + pkg, e);
   3501             } finally {
   3502                 try {
   3503                     out.flush();
   3504                     if (pipes != null) {
   3505                         if (pipes[0] != null) pipes[0].close();
   3506                         if (pipes[1] != null) pipes[1].close();
   3507                     }
   3508                 } catch (IOException e) {
   3509                     Slog.w(TAG, "I/O error closing down OBB backup", e);
   3510                 }
   3511             }
   3512             return success;
   3513         }
   3514 
   3515         public void restoreObbFile(String pkgName, ParcelFileDescriptor data,
   3516                 long fileSize, int type, String path, long mode, long mtime,
   3517                 int token, IBackupManager callbackBinder) {
   3518             waitForConnection();
   3519 
   3520             try {
   3521                 mService.restoreObbFile(pkgName, data, fileSize, type, path, mode, mtime,
   3522                         token, callbackBinder);
   3523             } catch (Exception e) {
   3524                 Slog.w(TAG, "Unable to restore OBBs for " + pkgName, e);
   3525             }
   3526         }
   3527 
   3528         private void waitForConnection() {
   3529             synchronized (this) {
   3530                 while (mService == null) {
   3531                     if (MORE_DEBUG) Slog.i(TAG, "...waiting for OBB service binding...");
   3532                     try {
   3533                         this.wait();
   3534                     } catch (InterruptedException e) { /* never interrupted */ }
   3535                 }
   3536                 if (MORE_DEBUG) Slog.i(TAG, "Connected to OBB service; continuing");
   3537             }
   3538         }
   3539 
   3540         @Override
   3541         public void onServiceConnected(ComponentName name, IBinder service) {
   3542             synchronized (this) {
   3543                 mService = IObbBackupService.Stub.asInterface(service);
   3544                 if (MORE_DEBUG) Slog.i(TAG, "OBB service connection " + mService
   3545                         + " connected on " + this);
   3546                 this.notifyAll();
   3547             }
   3548         }
   3549 
   3550         @Override
   3551         public void onServiceDisconnected(ComponentName name) {
   3552             synchronized (this) {
   3553                 mService = null;
   3554                 if (MORE_DEBUG) Slog.i(TAG, "OBB service connection disconnected on " + this);
   3555                 this.notifyAll();
   3556             }
   3557         }
   3558 
   3559     }
   3560 
   3561     private void routeSocketDataToOutput(ParcelFileDescriptor inPipe, OutputStream out)
   3562             throws IOException {
   3563         // We do not take close() responsibility for the pipe FD
   3564         FileInputStream raw = new FileInputStream(inPipe.getFileDescriptor());
   3565         DataInputStream in = new DataInputStream(raw);
   3566 
   3567         byte[] buffer = new byte[32 * 1024];
   3568         int chunkTotal;
   3569         while ((chunkTotal = in.readInt()) > 0) {
   3570             while (chunkTotal > 0) {
   3571                 int toRead = (chunkTotal > buffer.length) ? buffer.length : chunkTotal;
   3572                 int nRead = in.read(buffer, 0, toRead);
   3573                 out.write(buffer, 0, nRead);
   3574                 chunkTotal -= nRead;
   3575             }
   3576         }
   3577     }
   3578 
   3579     void tearDownAgentAndKill(ApplicationInfo app) {
   3580         if (app == null) {
   3581             // Null means the system package, so just quietly move on.  :)
   3582             return;
   3583         }
   3584 
   3585         try {
   3586             // unbind and tidy up even on timeout or failure, just in case
   3587             mActivityManager.unbindBackupAgent(app);
   3588 
   3589             // The agent was running with a stub Application object, so shut it down.
   3590             // !!! We hardcode the confirmation UI's package name here rather than use a
   3591             //     manifest flag!  TODO something less direct.
   3592             if (app.uid >= Process.FIRST_APPLICATION_UID
   3593                     && !app.packageName.equals("com.android.backupconfirm")) {
   3594                 if (MORE_DEBUG) Slog.d(TAG, "Killing agent host process");
   3595                 mActivityManager.killApplicationProcess(app.processName, app.uid);
   3596             } else {
   3597                 if (MORE_DEBUG) Slog.d(TAG, "Not killing after operation: " + app.processName);
   3598             }
   3599         } catch (RemoteException e) {
   3600             Slog.d(TAG, "Lost app trying to shut down");
   3601         }
   3602     }
   3603 
   3604     // Core logic for performing one package's full backup, gathering the tarball from the
   3605     // application and emitting it to the designated OutputStream.
   3606 
   3607     // Callout from the engine to an interested participant that might need to communicate
   3608     // with the agent prior to asking it to move data
   3609     interface FullBackupPreflight {
   3610         /**
   3611          * Perform the preflight operation necessary for the given package.
   3612          * @param pkg The name of the package being proposed for full-data backup
   3613          * @param agent Live BackupAgent binding to the target app's agent
   3614          * @return BackupTransport.TRANSPORT_OK to proceed with the backup operation,
   3615          *         or one of the other BackupTransport.* error codes as appropriate
   3616          */
   3617         int preflightFullBackup(PackageInfo pkg, IBackupAgent agent);
   3618 
   3619         long getExpectedSizeOrErrorCode();
   3620     };
   3621 
   3622     class FullBackupEngine {
   3623         OutputStream mOutput;
   3624         FullBackupPreflight mPreflightHook;
   3625         BackupRestoreTask mTimeoutMonitor;
   3626         IBackupAgent mAgent;
   3627         File mFilesDir;
   3628         File mManifestFile;
   3629         File mMetadataFile;
   3630         boolean mIncludeApks;
   3631         PackageInfo mPkg;
   3632 
   3633         class FullBackupRunner implements Runnable {
   3634             PackageInfo mPackage;
   3635             byte[] mWidgetData;
   3636             IBackupAgent mAgent;
   3637             ParcelFileDescriptor mPipe;
   3638             int mToken;
   3639             boolean mSendApk;
   3640             boolean mWriteManifest;
   3641 
   3642             FullBackupRunner(PackageInfo pack, IBackupAgent agent, ParcelFileDescriptor pipe,
   3643                              int token, boolean sendApk, boolean writeManifest, byte[] widgetData)
   3644                     throws IOException {
   3645                 mPackage = pack;
   3646                 mWidgetData = widgetData;
   3647                 mAgent = agent;
   3648                 mPipe = ParcelFileDescriptor.dup(pipe.getFileDescriptor());
   3649                 mToken = token;
   3650                 mSendApk = sendApk;
   3651                 mWriteManifest = writeManifest;
   3652             }
   3653 
   3654             @Override
   3655             public void run() {
   3656                 try {
   3657                     FullBackupDataOutput output = new FullBackupDataOutput(mPipe);
   3658 
   3659                     if (mWriteManifest) {
   3660                         final boolean writeWidgetData = mWidgetData != null;
   3661                         if (MORE_DEBUG) Slog.d(TAG, "Writing manifest for " + mPackage.packageName);
   3662                         writeAppManifest(mPackage, mManifestFile, mSendApk, writeWidgetData);
   3663                         FullBackup.backupToTar(mPackage.packageName, null, null,
   3664                                 mFilesDir.getAbsolutePath(),
   3665                                 mManifestFile.getAbsolutePath(),
   3666                                 output);
   3667                         mManifestFile.delete();
   3668 
   3669                         // We only need to write a metadata file if we have widget data to stash
   3670                         if (writeWidgetData) {
   3671                             writeMetadata(mPackage, mMetadataFile, mWidgetData);
   3672                             FullBackup.backupToTar(mPackage.packageName, null, null,
   3673                                     mFilesDir.getAbsolutePath(),
   3674                                     mMetadataFile.getAbsolutePath(),
   3675                                     output);
   3676                             mMetadataFile.delete();
   3677                         }
   3678                     }
   3679 
   3680                     if (mSendApk) {
   3681                         writeApkToBackup(mPackage, output);
   3682                     }
   3683 
   3684                     if (DEBUG) Slog.d(TAG, "Calling doFullBackup() on " + mPackage.packageName);
   3685                     prepareOperationTimeout(mToken, TIMEOUT_FULL_BACKUP_INTERVAL,
   3686                             mTimeoutMonitor /* in parent class */);
   3687                     mAgent.doFullBackup(mPipe, mToken, mBackupManagerBinder);
   3688                 } catch (IOException e) {
   3689                     Slog.e(TAG, "Error running full backup for " + mPackage.packageName);
   3690                 } catch (RemoteException e) {
   3691                     Slog.e(TAG, "Remote agent vanished during full backup of "
   3692                             + mPackage.packageName);
   3693                 } finally {
   3694                     try {
   3695                         mPipe.close();
   3696                     } catch (IOException e) {}
   3697                 }
   3698             }
   3699         }
   3700 
   3701         FullBackupEngine(OutputStream output, FullBackupPreflight preflightHook, PackageInfo pkg,
   3702                          boolean alsoApks, BackupRestoreTask timeoutMonitor) {
   3703             mOutput = output;
   3704             mPreflightHook = preflightHook;
   3705             mPkg = pkg;
   3706             mIncludeApks = alsoApks;
   3707             mTimeoutMonitor = timeoutMonitor;
   3708             mFilesDir = new File("/data/system");
   3709             mManifestFile = new File(mFilesDir, BACKUP_MANIFEST_FILENAME);
   3710             mMetadataFile = new File(mFilesDir, BACKUP_METADATA_FILENAME);
   3711         }
   3712 
   3713         public int preflightCheck() throws RemoteException {
   3714             if (mPreflightHook == null) {
   3715                 if (MORE_DEBUG) {
   3716                     Slog.v(TAG, "No preflight check");
   3717                 }
   3718                 return BackupTransport.TRANSPORT_OK;
   3719             }
   3720             if (initializeAgent()) {
   3721                 int result = mPreflightHook.preflightFullBackup(mPkg, mAgent);
   3722                 if (MORE_DEBUG) {
   3723                     Slog.v(TAG, "preflight returned " + result);
   3724                 }
   3725                 return result;
   3726             } else {
   3727                 Slog.w(TAG, "Unable to bind to full agent for " + mPkg.packageName);
   3728                 return BackupTransport.AGENT_ERROR;
   3729             }
   3730         }
   3731 
   3732         public int backupOnePackage() throws RemoteException {
   3733             int result = BackupTransport.AGENT_ERROR;
   3734 
   3735             if (initializeAgent()) {
   3736                 ParcelFileDescriptor[] pipes = null;
   3737                 try {
   3738                     pipes = ParcelFileDescriptor.createPipe();
   3739 
   3740                     ApplicationInfo app = mPkg.applicationInfo;
   3741                     final boolean isSharedStorage =
   3742                             mPkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE);
   3743                     final boolean sendApk = mIncludeApks
   3744                             && !isSharedStorage
   3745                             && ((app.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) == 0)
   3746                             && ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0 ||
   3747                             (app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
   3748 
   3749                     // TODO: http://b/22388012
   3750                     byte[] widgetBlob = AppWidgetBackupBridge.getWidgetState(mPkg.packageName,
   3751                             UserHandle.USER_SYSTEM);
   3752 
   3753                     final int token = generateToken();
   3754                     FullBackupRunner runner = new FullBackupRunner(mPkg, mAgent, pipes[1],
   3755                             token, sendApk, !isSharedStorage, widgetBlob);
   3756                     pipes[1].close();   // the runner has dup'd it
   3757                     pipes[1] = null;
   3758                     Thread t = new Thread(runner, "app-data-runner");
   3759                     t.start();
   3760 
   3761                     // Now pull data from the app and stuff it into the output
   3762                     routeSocketDataToOutput(pipes[0], mOutput);
   3763 
   3764                     if (!waitUntilOperationComplete(token)) {
   3765                         Slog.e(TAG, "Full backup failed on package " + mPkg.packageName);
   3766                     } else {
   3767                         if (MORE_DEBUG) {
   3768                             Slog.d(TAG, "Full package backup success: " + mPkg.packageName);
   3769                         }
   3770                         result = BackupTransport.TRANSPORT_OK;
   3771                     }
   3772                 } catch (IOException e) {
   3773                     Slog.e(TAG, "Error backing up " + mPkg.packageName + ": " + e.getMessage());
   3774                     result = BackupTransport.AGENT_ERROR;
   3775                 } finally {
   3776                     try {
   3777                         // flush after every package
   3778                         mOutput.flush();
   3779                         if (pipes != null) {
   3780                             if (pipes[0] != null) pipes[0].close();
   3781                             if (pipes[1] != null) pipes[1].close();
   3782                         }
   3783                     } catch (IOException e) {
   3784                         Slog.w(TAG, "Error bringing down backup stack");
   3785                         result = BackupTransport.TRANSPORT_ERROR;
   3786                     }
   3787                 }
   3788             } else {
   3789                 Slog.w(TAG, "Unable to bind to full agent for " + mPkg.packageName);
   3790             }
   3791             tearDown();
   3792             return result;
   3793         }
   3794 
   3795         public void sendQuotaExceeded(final long backupDataBytes, final long quotaBytes) {
   3796             if (initializeAgent()) {
   3797                 try {
   3798                     mAgent.doQuotaExceeded(backupDataBytes, quotaBytes);
   3799                 } catch (RemoteException e) {
   3800                     Slog.e(TAG, "Remote exception while telling agent about quota exceeded");
   3801                 }
   3802             }
   3803         }
   3804 
   3805         private boolean initializeAgent() {
   3806             if (mAgent == null) {
   3807                 if (MORE_DEBUG) {
   3808                     Slog.d(TAG, "Binding to full backup agent : " + mPkg.packageName);
   3809                 }
   3810                 mAgent = bindToAgentSynchronous(mPkg.applicationInfo,
   3811                         IApplicationThread.BACKUP_MODE_FULL);
   3812             }
   3813             return mAgent != null;
   3814         }
   3815 
   3816         private void writeApkToBackup(PackageInfo pkg, FullBackupDataOutput output) {
   3817             // Forward-locked apps, system-bundled .apks, etc are filtered out before we get here
   3818             // TODO: handle backing up split APKs
   3819             final String appSourceDir = pkg.applicationInfo.getBaseCodePath();
   3820             final String apkDir = new File(appSourceDir).getParent();
   3821             FullBackup.backupToTar(pkg.packageName, FullBackup.APK_TREE_TOKEN, null,
   3822                     apkDir, appSourceDir, output);
   3823 
   3824             // TODO: migrate this to SharedStorageBackup, since AID_SYSTEM
   3825             // doesn't have access to external storage.
   3826 
   3827             // Save associated .obb content if it exists and we did save the apk
   3828             // check for .obb and save those too
   3829             // TODO: http://b/22388012
   3830             final UserEnvironment userEnv = new UserEnvironment(UserHandle.USER_SYSTEM);
   3831             final File obbDir = userEnv.buildExternalStorageAppObbDirs(pkg.packageName)[0];
   3832             if (obbDir != null) {
   3833                 if (MORE_DEBUG) Log.i(TAG, "obb dir: " + obbDir.getAbsolutePath());
   3834                 File[] obbFiles = obbDir.listFiles();
   3835                 if (obbFiles != null) {
   3836                     final String obbDirName = obbDir.getAbsolutePath();
   3837                     for (File obb : obbFiles) {
   3838                         FullBackup.backupToTar(pkg.packageName, FullBackup.OBB_TREE_TOKEN, null,
   3839                                 obbDirName, obb.getAbsolutePath(), output);
   3840                     }
   3841                 }
   3842             }
   3843         }
   3844 
   3845         private void writeAppManifest(PackageInfo pkg, File manifestFile,
   3846                 boolean withApk, boolean withWidgets) throws IOException {
   3847             // Manifest format. All data are strings ending in LF:
   3848             //     BACKUP_MANIFEST_VERSION, currently 1
   3849             //
   3850             // Version 1:
   3851             //     package name
   3852             //     package's versionCode
   3853             //     platform versionCode
   3854             //     getInstallerPackageName() for this package (maybe empty)
   3855             //     boolean: "1" if archive includes .apk; any other string means not
   3856             //     number of signatures == N
   3857             // N*:    signature byte array in ascii format per Signature.toCharsString()
   3858             StringBuilder builder = new StringBuilder(4096);
   3859             StringBuilderPrinter printer = new StringBuilderPrinter(builder);
   3860 
   3861             printer.println(Integer.toString(BACKUP_MANIFEST_VERSION));
   3862             printer.println(pkg.packageName);
   3863             printer.println(Integer.toString(pkg.versionCode));
   3864             printer.println(Integer.toString(Build.VERSION.SDK_INT));
   3865 
   3866             String installerName = mPackageManager.getInstallerPackageName(pkg.packageName);
   3867             printer.println((installerName != null) ? installerName : "");
   3868 
   3869             printer.println(withApk ? "1" : "0");
   3870             if (pkg.signatures == null) {
   3871                 printer.println("0");
   3872             } else {
   3873                 printer.println(Integer.toString(pkg.signatures.length));
   3874                 for (Signature sig : pkg.signatures) {
   3875                     printer.println(sig.toCharsString());
   3876                 }
   3877             }
   3878 
   3879             FileOutputStream outstream = new FileOutputStream(manifestFile);
   3880             outstream.write(builder.toString().getBytes());
   3881             outstream.close();
   3882 
   3883             // We want the manifest block in the archive stream to be idempotent:
   3884             // each time we generate a backup stream for the app, we want the manifest
   3885             // block to be identical.  The underlying tar mechanism sees it as a file,
   3886             // though, and will propagate its mtime, causing the tar header to vary.
   3887             // Avoid this problem by pinning the mtime to zero.
   3888             manifestFile.setLastModified(0);
   3889         }
   3890 
   3891         // Widget metadata format. All header entries are strings ending in LF:
   3892         //
   3893         // Version 1 header:
   3894         //     BACKUP_METADATA_VERSION, currently "1"
   3895         //     package name
   3896         //
   3897         // File data (all integers are binary in network byte order)
   3898         // *N: 4 : integer token identifying which metadata blob
   3899         //     4 : integer size of this blob = N
   3900         //     N : raw bytes of this metadata blob
   3901         //
   3902         // Currently understood blobs (always in network byte order):
   3903         //
   3904         //     widgets : metadata token = 0x01FFED01 (BACKUP_WIDGET_METADATA_TOKEN)
   3905         //
   3906         // Unrecognized blobs are *ignored*, not errors.
   3907         private void writeMetadata(PackageInfo pkg, File destination, byte[] widgetData)
   3908                 throws IOException {
   3909             StringBuilder b = new StringBuilder(512);
   3910             StringBuilderPrinter printer = new StringBuilderPrinter(b);
   3911             printer.println(Integer.toString(BACKUP_METADATA_VERSION));
   3912             printer.println(pkg.packageName);
   3913 
   3914             FileOutputStream fout = new FileOutputStream(destination);
   3915             BufferedOutputStream bout = new BufferedOutputStream(fout);
   3916             DataOutputStream out = new DataOutputStream(bout);
   3917             bout.write(b.toString().getBytes());    // bypassing DataOutputStream
   3918 
   3919             if (widgetData != null && widgetData.length > 0) {
   3920                 out.writeInt(BACKUP_WIDGET_METADATA_TOKEN);
   3921                 out.writeInt(widgetData.length);
   3922                 out.write(widgetData);
   3923             }
   3924             bout.flush();
   3925             out.close();
   3926 
   3927             // As with the manifest file, guarantee idempotence of the archive metadata
   3928             // for the widget block by using a fixed mtime on the transient file.
   3929             destination.setLastModified(0);
   3930         }
   3931 
   3932         private void tearDown() {
   3933             if (mPkg != null) {
   3934                 tearDownAgentAndKill(mPkg.applicationInfo);
   3935             }
   3936         }
   3937     }
   3938 
   3939     // Generic driver skeleton for full backup operations
   3940     abstract class FullBackupTask implements Runnable {
   3941         IFullBackupRestoreObserver mObserver;
   3942 
   3943         FullBackupTask(IFullBackupRestoreObserver observer) {
   3944             mObserver = observer;
   3945         }
   3946 
   3947         // wrappers for observer use
   3948         final void sendStartBackup() {
   3949             if (mObserver != null) {
   3950                 try {
   3951                     mObserver.onStartBackup();
   3952                 } catch (RemoteException e) {
   3953                     Slog.w(TAG, "full backup observer went away: startBackup");
   3954                     mObserver = null;
   3955                 }
   3956             }
   3957         }
   3958 
   3959         final void sendOnBackupPackage(String name) {
   3960             if (mObserver != null) {
   3961                 try {
   3962                     // TODO: use a more user-friendly name string
   3963                     mObserver.onBackupPackage(name);
   3964                 } catch (RemoteException e) {
   3965                     Slog.w(TAG, "full backup observer went away: backupPackage");
   3966                     mObserver = null;
   3967                 }
   3968             }
   3969         }
   3970 
   3971         final void sendEndBackup() {
   3972             if (mObserver != null) {
   3973                 try {
   3974                     mObserver.onEndBackup();
   3975                 } catch (RemoteException e) {
   3976                     Slog.w(TAG, "full backup observer went away: endBackup");
   3977                     mObserver = null;
   3978                 }
   3979             }
   3980         }
   3981     }
   3982 
   3983     boolean deviceIsEncrypted() {
   3984         try {
   3985             return mMountService.getEncryptionState()
   3986                      != IMountService.ENCRYPTION_STATE_NONE
   3987                 && mMountService.getPasswordType()
   3988                      != StorageManager.CRYPT_TYPE_DEFAULT;
   3989         } catch (Exception e) {
   3990             // If we can't talk to the mount service we have a serious problem; fail
   3991             // "secure" i.e. assuming that the device is encrypted.
   3992             Slog.e(TAG, "Unable to communicate with mount service: " + e.getMessage());
   3993             return true;
   3994         }
   3995     }
   3996 
   3997     // Full backup task variant used for adb backup
   3998     class PerformAdbBackupTask extends FullBackupTask implements BackupRestoreTask {
   3999         FullBackupEngine mBackupEngine;
   4000         final AtomicBoolean mLatch;
   4001 
   4002         ParcelFileDescriptor mOutputFile;
   4003         DeflaterOutputStream mDeflater;
   4004         boolean mIncludeApks;
   4005         boolean mIncludeObbs;
   4006         boolean mIncludeShared;
   4007         boolean mDoWidgets;
   4008         boolean mAllApps;
   4009         boolean mIncludeSystem;
   4010         boolean mCompress;
   4011         ArrayList<String> mPackages;
   4012         PackageInfo mCurrentTarget;
   4013         String mCurrentPassword;
   4014         String mEncryptPassword;
   4015 
   4016         PerformAdbBackupTask(ParcelFileDescriptor fd, IFullBackupRestoreObserver observer,
   4017                 boolean includeApks, boolean includeObbs, boolean includeShared,
   4018                 boolean doWidgets, String curPassword, String encryptPassword, boolean doAllApps,
   4019                 boolean doSystem, boolean doCompress, String[] packages, AtomicBoolean latch) {
   4020             super(observer);
   4021             mLatch = latch;
   4022 
   4023             mOutputFile = fd;
   4024             mIncludeApks = includeApks;
   4025             mIncludeObbs = includeObbs;
   4026             mIncludeShared = includeShared;
   4027             mDoWidgets = doWidgets;
   4028             mAllApps = doAllApps;
   4029             mIncludeSystem = doSystem;
   4030             mPackages = (packages == null)
   4031                     ? new ArrayList<String>()
   4032                     : new ArrayList<String>(Arrays.asList(packages));
   4033             mCurrentPassword = curPassword;
   4034             // when backing up, if there is a current backup password, we require that
   4035             // the user use a nonempty encryption password as well.  if one is supplied
   4036             // in the UI we use that, but if the UI was left empty we fall back to the
   4037             // current backup password (which was supplied by the user as well).
   4038             if (encryptPassword == null || "".equals(encryptPassword)) {
   4039                 mEncryptPassword = curPassword;
   4040             } else {
   4041                 mEncryptPassword = encryptPassword;
   4042             }
   4043             if (MORE_DEBUG) {
   4044                 Slog.w(TAG, "Encrypting backup with passphrase=" + mEncryptPassword);
   4045             }
   4046             mCompress = doCompress;
   4047         }
   4048 
   4049         void addPackagesToSet(TreeMap<String, PackageInfo> set, List<String> pkgNames) {
   4050             for (String pkgName : pkgNames) {
   4051                 if (!set.containsKey(pkgName)) {
   4052                     try {
   4053                         PackageInfo info = mPackageManager.getPackageInfo(pkgName,
   4054                                 PackageManager.GET_SIGNATURES);
   4055                         set.put(pkgName, info);
   4056                     } catch (NameNotFoundException e) {
   4057                         Slog.w(TAG, "Unknown package " + pkgName + ", skipping");
   4058                     }
   4059                 }
   4060             }
   4061         }
   4062 
   4063         private OutputStream emitAesBackupHeader(StringBuilder headerbuf,
   4064                 OutputStream ofstream) throws Exception {
   4065             // User key will be used to encrypt the master key.
   4066             byte[] newUserSalt = randomBytes(PBKDF2_SALT_SIZE);
   4067             SecretKey userKey = buildPasswordKey(PBKDF_CURRENT, mEncryptPassword, newUserSalt,
   4068                     PBKDF2_HASH_ROUNDS);
   4069 
   4070             // the master key is random for each backup
   4071             byte[] masterPw = new byte[256 / 8];
   4072             mRng.nextBytes(masterPw);
   4073             byte[] checksumSalt = randomBytes(PBKDF2_SALT_SIZE);
   4074 
   4075             // primary encryption of the datastream with the random key
   4076             Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
   4077             SecretKeySpec masterKeySpec = new SecretKeySpec(masterPw, "AES");
   4078             c.init(Cipher.ENCRYPT_MODE, masterKeySpec);
   4079             OutputStream finalOutput = new CipherOutputStream(ofstream, c);
   4080 
   4081             // line 4: name of encryption algorithm
   4082             headerbuf.append(ENCRYPTION_ALGORITHM_NAME);
   4083             headerbuf.append('\n');
   4084             // line 5: user password salt [hex]
   4085             headerbuf.append(byteArrayToHex(newUserSalt));
   4086             headerbuf.append('\n');
   4087             // line 6: master key checksum salt [hex]
   4088             headerbuf.append(byteArrayToHex(checksumSalt));
   4089             headerbuf.append('\n');
   4090             // line 7: number of PBKDF2 rounds used [decimal]
   4091             headerbuf.append(PBKDF2_HASH_ROUNDS);
   4092             headerbuf.append('\n');
   4093 
   4094             // line 8: IV of the user key [hex]
   4095             Cipher mkC = Cipher.getInstance("AES/CBC/PKCS5Padding");
   4096             mkC.init(Cipher.ENCRYPT_MODE, userKey);
   4097 
   4098             byte[] IV = mkC.getIV();
   4099             headerbuf.append(byteArrayToHex(IV));
   4100             headerbuf.append('\n');
   4101 
   4102             // line 9: master IV + key blob, encrypted by the user key [hex].  Blob format:
   4103             //    [byte] IV length = Niv
   4104             //    [array of Niv bytes] IV itself
   4105             //    [byte] master key length = Nmk
   4106             //    [array of Nmk bytes] master key itself
   4107             //    [byte] MK checksum hash length = Nck
   4108             //    [array of Nck bytes] master key checksum hash
   4109             //
   4110             // The checksum is the (master key + checksum salt), run through the
   4111             // stated number of PBKDF2 rounds
   4112             IV = c.getIV();
   4113             byte[] mk = masterKeySpec.getEncoded();
   4114             byte[] checksum = makeKeyChecksum(PBKDF_CURRENT, masterKeySpec.getEncoded(),
   4115                     checksumSalt, PBKDF2_HASH_ROUNDS);
   4116 
   4117             ByteArrayOutputStream blob = new ByteArrayOutputStream(IV.length + mk.length
   4118                     + checksum.length + 3);
   4119             DataOutputStream mkOut = new DataOutputStream(blob);
   4120             mkOut.writeByte(IV.length);
   4121             mkOut.write(IV);
   4122             mkOut.writeByte(mk.length);
   4123             mkOut.write(mk);
   4124             mkOut.writeByte(checksum.length);
   4125             mkOut.write(checksum);
   4126             mkOut.flush();
   4127             byte[] encryptedMk = mkC.doFinal(blob.toByteArray());
   4128             headerbuf.append(byteArrayToHex(encryptedMk));
   4129             headerbuf.append('\n');
   4130 
   4131             return finalOutput;
   4132         }
   4133 
   4134         private void finalizeBackup(OutputStream out) {
   4135             try {
   4136                 // A standard 'tar' EOF sequence: two 512-byte blocks of all zeroes.
   4137                 byte[] eof = new byte[512 * 2]; // newly allocated == zero filled
   4138                 out.write(eof);
   4139             } catch (IOException e) {
   4140                 Slog.w(TAG, "Error attempting to finalize backup stream");
   4141             }
   4142         }
   4143 
   4144         @Override
   4145         public void run() {
   4146             Slog.i(TAG, "--- Performing full-dataset adb backup ---");
   4147 
   4148             TreeMap<String, PackageInfo> packagesToBackup = new TreeMap<String, PackageInfo>();
   4149             FullBackupObbConnection obbConnection = new FullBackupObbConnection();
   4150             obbConnection.establish();  // we'll want this later
   4151 
   4152             sendStartBackup();
   4153 
   4154             // doAllApps supersedes the package set if any
   4155             if (mAllApps) {
   4156                 List<PackageInfo> allPackages = mPackageManager.getInstalledPackages(
   4157                         PackageManager.GET_SIGNATURES);
   4158                 for (int i = 0; i < allPackages.size(); i++) {
   4159                     PackageInfo pkg = allPackages.get(i);
   4160                     // Exclude system apps if we've been asked to do so
   4161                     if (mIncludeSystem == true
   4162                             || ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0)) {
   4163                         packagesToBackup.put(pkg.packageName, pkg);
   4164                     }
   4165                 }
   4166             }
   4167 
   4168             // If we're doing widget state as well, ensure that we have all the involved
   4169             // host & provider packages in the set
   4170             if (mDoWidgets) {
   4171                 // TODO: http://b/22388012
   4172                 List<String> pkgs =
   4173                         AppWidgetBackupBridge.getWidgetParticipants(UserHandle.USER_SYSTEM);
   4174                 if (pkgs != null) {
   4175                     if (MORE_DEBUG) {
   4176                         Slog.i(TAG, "Adding widget participants to backup set:");
   4177                         StringBuilder sb = new StringBuilder(128);
   4178                         sb.append("   ");
   4179                         for (String s : pkgs) {
   4180                             sb.append(' ');
   4181                             sb.append(s);
   4182                         }
   4183                         Slog.i(TAG, sb.toString());
   4184                     }
   4185                     addPackagesToSet(packagesToBackup, pkgs);
   4186                 }
   4187             }
   4188 
   4189             // Now process the command line argument packages, if any. Note that explicitly-
   4190             // named system-partition packages will be included even if includeSystem was
   4191             // set to false.
   4192             if (mPackages != null) {
   4193                 addPackagesToSet(packagesToBackup, mPackages);
   4194             }
   4195 
   4196             // Now we cull any inapplicable / inappropriate packages from the set.  This
   4197             // includes the special shared-storage agent package; we handle that one
   4198             // explicitly at the end of the backup pass.
   4199             Iterator<Entry<String, PackageInfo>> iter = packagesToBackup.entrySet().iterator();
   4200             while (iter.hasNext()) {
   4201                 PackageInfo pkg = iter.next().getValue();
   4202                 if (!appIsEligibleForBackup(pkg.applicationInfo)
   4203                         || appIsStopped(pkg.applicationInfo)
   4204                         || appIsKeyValueOnly(pkg)) {
   4205                     iter.remove();
   4206                 }
   4207             }
   4208 
   4209             // flatten the set of packages now so we can explicitly control the ordering
   4210             ArrayList<PackageInfo> backupQueue =
   4211                     new ArrayList<PackageInfo>(packagesToBackup.values());
   4212             FileOutputStream ofstream = new FileOutputStream(mOutputFile.getFileDescriptor());
   4213             OutputStream out = null;
   4214 
   4215             PackageInfo pkg = null;
   4216             try {
   4217                 boolean encrypting = (mEncryptPassword != null && mEncryptPassword.length() > 0);
   4218 
   4219                 // Only allow encrypted backups of encrypted devices
   4220                 if (deviceIsEncrypted() && !encrypting) {
   4221                     Slog.e(TAG, "Unencrypted backup of encrypted device; aborting");
   4222                     return;
   4223                 }
   4224 
   4225                 OutputStream finalOutput = ofstream;
   4226 
   4227                 // Verify that the given password matches the currently-active
   4228                 // backup password, if any
   4229                 if (!backupPasswordMatches(mCurrentPassword)) {
   4230                     if (DEBUG) Slog.w(TAG, "Backup password mismatch; aborting");
   4231                     return;
   4232                 }
   4233 
   4234                 // Write the global file header.  All strings are UTF-8 encoded; lines end
   4235                 // with a '\n' byte.  Actual backup data begins immediately following the
   4236                 // final '\n'.
   4237                 //
   4238                 // line 1: "ANDROID BACKUP"
   4239                 // line 2: backup file format version, currently "2"
   4240                 // line 3: compressed?  "0" if not compressed, "1" if compressed.
   4241                 // line 4: name of encryption algorithm [currently only "none" or "AES-256"]
   4242                 //
   4243                 // When line 4 is not "none", then additional header data follows:
   4244                 //
   4245                 // line 5: user password salt [hex]
   4246                 // line 6: master key checksum salt [hex]
   4247                 // line 7: number of PBKDF2 rounds to use (same for user & master) [decimal]
   4248                 // line 8: IV of the user key [hex]
   4249                 // line 9: master key blob [hex]
   4250                 //     IV of the master key, master key itself, master key checksum hash
   4251                 //
   4252                 // The master key checksum is the master key plus its checksum salt, run through
   4253                 // 10k rounds of PBKDF2.  This is used to verify that the user has supplied the
   4254                 // correct password for decrypting the archive:  the master key decrypted from
   4255                 // the archive using the user-supplied password is also run through PBKDF2 in
   4256                 // this way, and if the result does not match the checksum as stored in the
   4257                 // archive, then we know that the user-supplied password does not match the
   4258                 // archive's.
   4259                 StringBuilder headerbuf = new StringBuilder(1024);
   4260 
   4261                 headerbuf.append(BACKUP_FILE_HEADER_MAGIC);
   4262                 headerbuf.append(BACKUP_FILE_VERSION); // integer, no trailing \n
   4263                 headerbuf.append(mCompress ? "\n1\n" : "\n0\n");
   4264 
   4265                 try {
   4266                     // Set up the encryption stage if appropriate, and emit the correct header
   4267                     if (encrypting) {
   4268                         finalOutput = emitAesBackupHeader(headerbuf, finalOutput);
   4269                     } else {
   4270                         headerbuf.append("none\n");
   4271                     }
   4272 
   4273                     byte[] header = headerbuf.toString().getBytes("UTF-8");
   4274                     ofstream.write(header);
   4275 
   4276                     // Set up the compression stage feeding into the encryption stage (if any)
   4277                     if (mCompress) {
   4278                         Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION);
   4279                         finalOutput = new DeflaterOutputStream(finalOutput, deflater, true);
   4280                     }
   4281 
   4282                     out = finalOutput;
   4283                 } catch (Exception e) {
   4284                     // Should never happen!
   4285                     Slog.e(TAG, "Unable to emit archive header", e);
   4286                     return;
   4287                 }
   4288 
   4289                 // Shared storage if requested
   4290                 if (mIncludeShared) {
   4291                     try {
   4292                         pkg = mPackageManager.getPackageInfo(SHARED_BACKUP_AGENT_PACKAGE, 0);
   4293                         backupQueue.add(pkg);
   4294                     } catch (NameNotFoundException e) {
   4295                         Slog.e(TAG, "Unable to find shared-storage backup handler");
   4296                     }
   4297                 }
   4298 
   4299                 // Now actually run the constructed backup sequence
   4300                 int N = backupQueue.size();
   4301                 for (int i = 0; i < N; i++) {
   4302                     pkg = backupQueue.get(i);
   4303                     final boolean isSharedStorage =
   4304                             pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE);
   4305 
   4306                     mBackupEngine = new FullBackupEngine(out, null, pkg, mIncludeApks, this);
   4307                     sendOnBackupPackage(isSharedStorage ? "Shared storage" : pkg.packageName);
   4308 
   4309                     // Don't need to check preflight result as there is no preflight hook.
   4310                     mCurrentTarget = pkg;
   4311                     mBackupEngine.backupOnePackage();
   4312 
   4313                     // after the app's agent runs to handle its private filesystem
   4314                     // contents, back up any OBB content it has on its behalf.
   4315                     if (mIncludeObbs) {
   4316                         boolean obbOkay = obbConnection.backupObbs(pkg, out);
   4317                         if (!obbOkay) {
   4318                             throw new RuntimeException("Failure writing OBB stack for " + pkg);
   4319                         }
   4320                     }
   4321                 }
   4322 
   4323                 // Done!
   4324                 finalizeBackup(out);
   4325             } catch (RemoteException e) {
   4326                 Slog.e(TAG, "App died during full backup");
   4327             } catch (Exception e) {
   4328                 Slog.e(TAG, "Internal exception during full backup", e);
   4329             } finally {
   4330                 try {
   4331                     if (out != null) {
   4332                         out.flush();
   4333                         out.close();
   4334                     }
   4335                     mOutputFile.close();
   4336                 } catch (IOException e) {
   4337                     /* nothing we can do about this */
   4338                 }
   4339                 synchronized (mCurrentOpLock) {
   4340                     mCurrentOperations.clear();
   4341                 }
   4342                 synchronized (mLatch) {
   4343                     mLatch.set(true);
   4344                     mLatch.notifyAll();
   4345                 }
   4346                 sendEndBackup();
   4347                 obbConnection.tearDown();
   4348                 if (DEBUG) Slog.d(TAG, "Full backup pass complete.");
   4349                 mWakelock.release();
   4350             }
   4351         }
   4352 
   4353         // BackupRestoreTask methods, used for timeout handling
   4354         @Override
   4355         public void execute() {
   4356             // Unused
   4357         }
   4358 
   4359         @Override
   4360         public void operationComplete(long result) {
   4361             // Unused
   4362         }
   4363 
   4364         @Override
   4365         public void handleTimeout() {
   4366             final PackageInfo target = mCurrentTarget;
   4367             if (DEBUG) {
   4368                 Slog.w(TAG, "adb backup timeout of " + target);
   4369             }
   4370             if (target != null) {
   4371                 tearDownAgentAndKill(mCurrentTarget.applicationInfo);
   4372             }
   4373         }
   4374     }
   4375 
   4376     // Full backup task extension used for transport-oriented operation
   4377     class PerformFullTransportBackupTask extends FullBackupTask {
   4378         static final String TAG = "PFTBT";
   4379         ArrayList<PackageInfo> mPackages;
   4380         boolean mUpdateSchedule;
   4381         CountDownLatch mLatch;
   4382         AtomicBoolean mKeepRunning;     // signal from job scheduler
   4383         FullBackupJob mJob;             // if a scheduled job needs to be finished afterwards
   4384         IBackupObserver mBackupObserver;
   4385         boolean mUserInitiated;
   4386 
   4387         PerformFullTransportBackupTask(IFullBackupRestoreObserver observer,
   4388                 String[] whichPackages, boolean updateSchedule,
   4389                 FullBackupJob runningJob, CountDownLatch latch, IBackupObserver backupObserver,
   4390                 boolean userInitiated) {
   4391             super(observer);
   4392             mUpdateSchedule = updateSchedule;
   4393             mLatch = latch;
   4394             mKeepRunning = new AtomicBoolean(true);
   4395             mJob = runningJob;
   4396             mPackages = new ArrayList<PackageInfo>(whichPackages.length);
   4397             mBackupObserver = backupObserver;
   4398             mUserInitiated = userInitiated;
   4399 
   4400             for (String pkg : whichPackages) {
   4401                 try {
   4402                     PackageInfo info = mPackageManager.getPackageInfo(pkg,
   4403                             PackageManager.GET_SIGNATURES);
   4404                     if (!appIsEligibleForBackup(info.applicationInfo)) {
   4405                         // Cull any packages that have indicated that backups are not permitted,
   4406                         // that run as system-domain uids but do not define their own backup agents,
   4407                         // as well as any explicit mention of the 'special' shared-storage agent
   4408                         // package (we handle that one at the end).
   4409                         if (MORE_DEBUG) {
   4410                             Slog.d(TAG, "Ignoring ineligible package " + pkg);
   4411                         }
   4412                         sendBackupOnPackageResult(mBackupObserver, pkg,
   4413                             BackupManager.ERROR_BACKUP_NOT_ALLOWED);
   4414                         continue;
   4415                     } else if (!appGetsFullBackup(info)) {
   4416                         // Cull any packages that are found in the queue but now aren't supposed
   4417                         // to get full-data backup operations.
   4418                         if (MORE_DEBUG) {
   4419                             Slog.d(TAG, "Ignoring full-data backup of key/value participant "
   4420                                     + pkg);
   4421                         }
   4422                         sendBackupOnPackageResult(mBackupObserver, pkg,
   4423                                 BackupManager.ERROR_BACKUP_NOT_ALLOWED);
   4424                         continue;
   4425                     } else if (appIsStopped(info.applicationInfo)) {
   4426                         // Cull any packages in the 'stopped' state: they've either just been
   4427                         // installed or have explicitly been force-stopped by the user.  In both
   4428                         // cases we do not want to launch them for backup.
   4429                         if (MORE_DEBUG) {
   4430                             Slog.d(TAG, "Ignoring stopped package " + pkg);
   4431                         }
   4432                         sendBackupOnPackageResult(mBackupObserver, pkg,
   4433                                 BackupManager.ERROR_BACKUP_NOT_ALLOWED);
   4434                         continue;
   4435                     }
   4436                     mPackages.add(info);
   4437                 } catch (NameNotFoundException e) {
   4438                     Slog.i(TAG, "Requested package " + pkg + " not found; ignoring");
   4439                 }
   4440             }
   4441         }
   4442 
   4443         public void setRunning(boolean running) {
   4444             mKeepRunning.set(running);
   4445         }
   4446 
   4447         @Override
   4448         public void run() {
   4449             // data from the app, passed to us for bridging to the transport
   4450             ParcelFileDescriptor[] enginePipes = null;
   4451 
   4452             // Pipe through which we write data to the transport
   4453             ParcelFileDescriptor[] transportPipes = null;
   4454 
   4455             long backoff = 0;
   4456             int backupRunStatus = BackupManager.SUCCESS;
   4457 
   4458             try {
   4459                 if (!mEnabled || !mProvisioned) {
   4460                     // Backups are globally disabled, so don't proceed.
   4461                     if (DEBUG) {
   4462                         Slog.i(TAG, "full backup requested but e=" + mEnabled
   4463                                 + " p=" + mProvisioned + "; ignoring");
   4464                     }
   4465                     mUpdateSchedule = false;
   4466                     backupRunStatus = BackupManager.ERROR_BACKUP_NOT_ALLOWED;
   4467                     return;
   4468                 }
   4469 
   4470                 IBackupTransport transport = getTransport(mCurrentTransport);
   4471                 if (transport == null) {
   4472                     Slog.w(TAG, "Transport not present; full data backup not performed");
   4473                     backupRunStatus = BackupManager.ERROR_TRANSPORT_ABORTED;
   4474                     return;
   4475                 }
   4476 
   4477                 // Set up to send data to the transport
   4478                 final int N = mPackages.size();
   4479                 final byte[] buffer = new byte[8192];
   4480                 for (int i = 0; i < N; i++) {
   4481                     PackageInfo currentPackage = mPackages.get(i);
   4482                     String packageName = currentPackage.packageName;
   4483                     if (DEBUG) {
   4484                         Slog.i(TAG, "Initiating full-data transport backup of " + packageName);
   4485                     }
   4486                     EventLog.writeEvent(EventLogTags.FULL_BACKUP_PACKAGE, packageName);
   4487 
   4488                     transportPipes = ParcelFileDescriptor.createPipe();
   4489 
   4490                     // Tell the transport the data's coming
   4491                     int flags = mUserInitiated ? BackupTransport.FLAG_USER_INITIATED : 0;
   4492                     int backupPackageStatus = transport.performFullBackup(currentPackage,
   4493                             transportPipes[0], flags);
   4494                     if (backupPackageStatus == BackupTransport.TRANSPORT_OK) {
   4495                         // The transport has its own copy of the read end of the pipe,
   4496                         // so close ours now
   4497                         transportPipes[0].close();
   4498                         transportPipes[0] = null;
   4499 
   4500                         // Now set up the backup engine / data source end of things
   4501                         enginePipes = ParcelFileDescriptor.createPipe();
   4502                         SinglePackageBackupRunner backupRunner =
   4503                                 new SinglePackageBackupRunner(enginePipes[1], currentPackage,
   4504                                         transport);
   4505                         // The runner dup'd the pipe half, so we close it here
   4506                         enginePipes[1].close();
   4507                         enginePipes[1] = null;
   4508 
   4509                         // Spin off the runner to fetch the app's data and pipe it
   4510                         // into the engine pipes
   4511                         (new Thread(backupRunner, "package-backup-bridge")).start();
   4512 
   4513                         // Read data off the engine pipe and pass it to the transport
   4514                         // pipe until we hit EOD on the input stream.  We do not take
   4515                         // close() responsibility for these FDs into these stream wrappers.
   4516                         FileInputStream in = new FileInputStream(
   4517                                 enginePipes[0].getFileDescriptor());
   4518                         FileOutputStream out = new FileOutputStream(
   4519                                 transportPipes[1].getFileDescriptor());
   4520                         long totalRead = 0;
   4521                         final long preflightResult = backupRunner.getPreflightResultBlocking();
   4522                         // Preflight result is negative if some error happened on preflight.
   4523                         if (preflightResult < 0) {
   4524                             if (MORE_DEBUG) {
   4525                                 Slog.d(TAG, "Backup error after preflight of package "
   4526                                         + packageName + ": " + preflightResult
   4527                                         + ", not running backup.");
   4528                             }
   4529                             backupPackageStatus = (int) preflightResult;
   4530                         } else {
   4531                             int nRead = 0;
   4532                             do {
   4533                                 if (!mKeepRunning.get()) {
   4534                                     if (DEBUG_SCHEDULING) {
   4535                                         Slog.i(TAG, "Full backup task told to stop");
   4536                                     }
   4537                                     break;
   4538                                 }
   4539                                 nRead = in.read(buffer);
   4540                                 if (MORE_DEBUG) {
   4541                                     Slog.v(TAG, "in.read(buffer) from app: " + nRead);
   4542                                 }
   4543                                 if (nRead > 0) {
   4544                                     out.write(buffer, 0, nRead);
   4545                                     backupPackageStatus = transport.sendBackupData(nRead);
   4546                                     totalRead += nRead;
   4547                                     if (mBackupObserver != null && preflightResult > 0) {
   4548                                         sendBackupOnUpdate(mBackupObserver, packageName,
   4549                                                 new BackupProgress(preflightResult, totalRead));
   4550                                     }
   4551                                 }
   4552                             } while (nRead > 0
   4553                                     && backupPackageStatus == BackupTransport.TRANSPORT_OK);
   4554 
   4555                             // Despite preflight succeeded, package still can hit quota on flight.
   4556                             if (backupPackageStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
   4557                                 long quota = transport.getBackupQuota(packageName, true);
   4558                                 Slog.w(TAG, "Package hit quota limit in-flight " + packageName
   4559                                         + ": " + totalRead + " of " + quota);
   4560                                 backupRunner.sendQuotaExceeded(totalRead, quota);
   4561                             }
   4562                         }
   4563 
   4564                         // If we've lost our running criteria, tell the transport to cancel
   4565                         // and roll back this (partial) backup payload; otherwise tell it
   4566                         // that we've reached the clean finish state.
   4567                         if (!mKeepRunning.get()) {
   4568                             backupPackageStatus = BackupTransport.TRANSPORT_ERROR;
   4569                             transport.cancelFullBackup();
   4570                         } else {
   4571                             // If we were otherwise in a good state, now interpret the final
   4572                             // result based on what finishBackup() returns.  If we're in a
   4573                             // failure case already, preserve that result and ignore whatever
   4574                             // finishBackup() reports.
   4575                             final int finishResult = transport.finishBackup();
   4576                             if (backupPackageStatus == BackupTransport.TRANSPORT_OK) {
   4577                                 backupPackageStatus = finishResult;
   4578                             }
   4579                         }
   4580 
   4581                         // A transport-originated error here means that we've hit an error that the
   4582                         // runner doesn't know about, so it's still moving data but we're pulling the
   4583                         // rug out from under it.  Don't ask for its result:  we already know better
   4584                         // and we'll hang if we block waiting for it, since it relies on us to
   4585                         // read back the data it's writing into the engine.  Just proceed with
   4586                         // a graceful failure.  The runner/engine mechanism will tear itself
   4587                         // down cleanly when we close the pipes from this end.  Transport-level
   4588                         // errors take precedence over agent/app-specific errors for purposes of
   4589                         // determining our course of action.
   4590                         if (backupPackageStatus == BackupTransport.TRANSPORT_OK) {
   4591                             // We still could fail in backup runner thread, getting result from there.
   4592                             int backupRunnerResult = backupRunner.getBackupResultBlocking();
   4593                             if (backupRunnerResult != BackupTransport.TRANSPORT_OK) {
   4594                                 // If there was an error in runner thread and
   4595                                 // not TRANSPORT_ERROR here, overwrite it.
   4596                                 backupPackageStatus = backupRunnerResult;
   4597                             }
   4598                         } else {
   4599                             if (MORE_DEBUG) {
   4600                                 Slog.i(TAG, "Transport-level failure; cancelling agent work");
   4601                             }
   4602                         }
   4603 
   4604                         if (MORE_DEBUG) {
   4605                             Slog.i(TAG, "Done delivering backup data: result="
   4606                                     + backupPackageStatus);
   4607                         }
   4608 
   4609                         if (backupPackageStatus != BackupTransport.TRANSPORT_OK) {
   4610                             Slog.e(TAG, "Error " + backupPackageStatus + " backing up "
   4611                                     + packageName);
   4612                         }
   4613 
   4614                         // Also ask the transport how long it wants us to wait before
   4615                         // moving on to the next package, if any.
   4616                         backoff = transport.requestFullBackupTime();
   4617                         if (DEBUG_SCHEDULING) {
   4618                             Slog.i(TAG, "Transport suggested backoff=" + backoff);
   4619                         }
   4620 
   4621                     }
   4622 
   4623                     // Roll this package to the end of the backup queue if we're
   4624                     // in a queue-driven mode (regardless of success/failure)
   4625                     if (mUpdateSchedule) {
   4626                         enqueueFullBackup(packageName, System.currentTimeMillis());
   4627                     }
   4628 
   4629                     if (backupPackageStatus == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
   4630                         sendBackupOnPackageResult(mBackupObserver, packageName,
   4631                                 BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED);
   4632                         if (DEBUG) {
   4633                             Slog.i(TAG, "Transport rejected backup of " + packageName
   4634                                     + ", skipping");
   4635                         }
   4636                         EventLog.writeEvent(EventLogTags.FULL_BACKUP_AGENT_FAILURE, packageName,
   4637                                 "transport rejected");
   4638                         // Do nothing, clean up, and continue looping.
   4639                     } else if (backupPackageStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
   4640                         sendBackupOnPackageResult(mBackupObserver, packageName,
   4641                                 BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED);
   4642                         if (DEBUG) {
   4643                             Slog.i(TAG, "Transport quota exceeded for package: " + packageName);
   4644                             EventLog.writeEvent(EventLogTags.FULL_BACKUP_QUOTA_EXCEEDED,
   4645                                     packageName);
   4646                         }
   4647                         // Do nothing, clean up, and continue looping.
   4648                     } else if (backupPackageStatus == BackupTransport.AGENT_ERROR) {
   4649                         sendBackupOnPackageResult(mBackupObserver, packageName,
   4650                                 BackupManager.ERROR_AGENT_FAILURE);
   4651                         Slog.w(TAG, "Application failure for package: " + packageName);
   4652                         EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName);
   4653                         tearDownAgentAndKill(currentPackage.applicationInfo);
   4654                         // Do nothing, clean up, and continue looping.
   4655                     } else if (backupPackageStatus != BackupTransport.TRANSPORT_OK) {
   4656                         sendBackupOnPackageResult(mBackupObserver, packageName,
   4657                             BackupManager.ERROR_TRANSPORT_ABORTED);
   4658                         Slog.w(TAG, "Transport failed; aborting backup: " + backupPackageStatus);
   4659                         EventLog.writeEvent(EventLogTags.FULL_BACKUP_TRANSPORT_FAILURE);
   4660                         // Abort entire backup pass.
   4661                         backupRunStatus = BackupManager.ERROR_TRANSPORT_ABORTED;
   4662                         return;
   4663                     } else {
   4664                         // Success!
   4665                         sendBackupOnPackageResult(mBackupObserver, packageName,
   4666                                 BackupManager.SUCCESS);
   4667                         EventLog.writeEvent(EventLogTags.FULL_BACKUP_SUCCESS, packageName);
   4668                         logBackupComplete(packageName);
   4669                     }
   4670                     cleanUpPipes(transportPipes);
   4671                     cleanUpPipes(enginePipes);
   4672                     if (currentPackage.applicationInfo != null) {
   4673                         Slog.i(TAG, "Unbinding agent in " + packageName);
   4674                         addBackupTrace("unbinding " + packageName);
   4675                         try {
   4676                             mActivityManager.unbindBackupAgent(currentPackage.applicationInfo);
   4677                         } catch (RemoteException e) { /* can't happen; activity manager is local */ }
   4678                     }
   4679                 }
   4680             } catch (Exception e) {
   4681                 backupRunStatus = BackupManager.ERROR_TRANSPORT_ABORTED;
   4682                 Slog.w(TAG, "Exception trying full transport backup", e);
   4683             } finally {
   4684                 if (DEBUG) {
   4685                     Slog.i(TAG, "Full backup completed with status: " + backupRunStatus);
   4686                 }
   4687                 sendBackupFinished(mBackupObserver, backupRunStatus);
   4688 
   4689                 cleanUpPipes(transportPipes);
   4690                 cleanUpPipes(enginePipes);
   4691 
   4692                 if (mJob != null) {
   4693                     mJob.finishBackupPass();
   4694                 }
   4695 
   4696                 synchronized (mQueueLock) {
   4697                     mRunningFullBackupTask = null;
   4698                 }
   4699 
   4700                 mLatch.countDown();
   4701 
   4702                 // Now that we're actually done with schedule-driven work, reschedule
   4703                 // the next pass based on the new queue state.
   4704                 if (mUpdateSchedule) {
   4705                     scheduleNextFullBackupJob(backoff);
   4706                 }
   4707                 Slog.i(BackupManagerService.TAG, "Full data backup pass finished.");
   4708                 mWakelock.release();
   4709             }
   4710         }
   4711 
   4712         void cleanUpPipes(ParcelFileDescriptor[] pipes) {
   4713             if (pipes != null) {
   4714                 if (pipes[0] != null) {
   4715                     ParcelFileDescriptor fd = pipes[0];
   4716                     pipes[0] = null;
   4717                     try {
   4718                         fd.close();
   4719                     } catch (IOException e) {
   4720                         Slog.w(TAG, "Unable to close pipe!");
   4721                     }
   4722                 }
   4723                 if (pipes[1] != null) {
   4724                     ParcelFileDescriptor fd = pipes[1];
   4725                     pipes[1] = null;
   4726                     try {
   4727                         fd.close();
   4728                     } catch (IOException e) {
   4729                         Slog.w(TAG, "Unable to close pipe!");
   4730                     }
   4731                 }
   4732             }
   4733         }
   4734 
   4735         // Run the backup and pipe it back to the given socket -- expects to run on
   4736         // a standalone thread.  The  runner owns this half of the pipe, and closes
   4737         // it to indicate EOD to the other end.
   4738         class SinglePackageBackupPreflight implements BackupRestoreTask, FullBackupPreflight {
   4739             final AtomicLong mResult = new AtomicLong(BackupTransport.AGENT_ERROR);
   4740             final CountDownLatch mLatch = new CountDownLatch(1);
   4741             final IBackupTransport mTransport;
   4742 
   4743             public SinglePackageBackupPreflight(IBackupTransport transport) {
   4744                 mTransport = transport;
   4745             }
   4746 
   4747             @Override
   4748             public int preflightFullBackup(PackageInfo pkg, IBackupAgent agent) {
   4749                 int result;
   4750                 try {
   4751                     final int token = generateToken();
   4752                     prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL, this);
   4753                     addBackupTrace("preflighting");
   4754                     if (MORE_DEBUG) {
   4755                         Slog.d(TAG, "Preflighting full payload of " + pkg.packageName);
   4756                     }
   4757                     agent.doMeasureFullBackup(token, mBackupManagerBinder);
   4758 
   4759                     // Now wait to get our result back.  If this backstop timeout is reached without
   4760                     // the latch being thrown, flow will continue as though a result or "normal"
   4761                     // timeout had been produced.  In case of a real backstop timeout, mResult
   4762                     // will still contain the value it was constructed with, AGENT_ERROR, which
   4763                     // intentionaly falls into the "just report failure" code.
   4764                     mLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS);
   4765 
   4766                     long totalSize = mResult.get();
   4767                     // If preflight timed out, mResult will contain error code as int.
   4768                     if (totalSize < 0) {
   4769                         return (int) totalSize;
   4770                     }
   4771                     if (MORE_DEBUG) {
   4772                         Slog.v(TAG, "Got preflight response; size=" + totalSize);
   4773                     }
   4774 
   4775                     result = mTransport.checkFullBackupSize(totalSize);
   4776                     if (result == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
   4777                         final long quota = mTransport.getBackupQuota(pkg.packageName, true);
   4778                         if (MORE_DEBUG) {
   4779                             Slog.d(TAG, "Package hit quota limit on preflight " +
   4780                                     pkg.packageName + ": " + totalSize + " of " + quota);
   4781                         }
   4782                         agent.doQuotaExceeded(totalSize, quota);
   4783                     }
   4784                 } catch (Exception e) {
   4785                     Slog.w(TAG, "Exception preflighting " + pkg.packageName + ": " + e.getMessage());
   4786                     result = BackupTransport.AGENT_ERROR;
   4787                 }
   4788                 return result;
   4789             }
   4790 
   4791             @Override
   4792             public void execute() {
   4793                 // Unused in this case
   4794             }
   4795 
   4796             @Override
   4797             public void operationComplete(long result) {
   4798                 // got the callback, and our preflightFullBackup() method is waiting for the result
   4799                 if (MORE_DEBUG) {
   4800                     Slog.i(TAG, "Preflight op complete, result=" + result);
   4801                 }
   4802                 mResult.set(result);
   4803                 mLatch.countDown();
   4804             }
   4805 
   4806             @Override
   4807             public void handleTimeout() {
   4808                 if (MORE_DEBUG) {
   4809                     Slog.i(TAG, "Preflight timeout; failing");
   4810                 }
   4811                 mResult.set(BackupTransport.AGENT_ERROR);
   4812                 mLatch.countDown();
   4813             }
   4814 
   4815             @Override
   4816             public long getExpectedSizeOrErrorCode() {
   4817                 try {
   4818                     mLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS);
   4819                     return mResult.get();
   4820                 } catch (InterruptedException e) {
   4821                     return BackupTransport.NO_MORE_DATA;
   4822                 }
   4823             }
   4824         }
   4825 
   4826         class SinglePackageBackupRunner implements Runnable, BackupRestoreTask {
   4827             final ParcelFileDescriptor mOutput;
   4828             final PackageInfo mTarget;
   4829             final FullBackupPreflight mPreflight;
   4830             final CountDownLatch mPreflightLatch;
   4831             final CountDownLatch mBackupLatch;
   4832             private FullBackupEngine mEngine;
   4833             private volatile int mPreflightResult;
   4834             private volatile int mBackupResult;
   4835 
   4836             SinglePackageBackupRunner(ParcelFileDescriptor output, PackageInfo target,
   4837                     IBackupTransport transport) throws IOException {
   4838                 mOutput = ParcelFileDescriptor.dup(output.getFileDescriptor());
   4839                 mTarget = target;
   4840                 mPreflight = new SinglePackageBackupPreflight(transport);
   4841                 mPreflightLatch = new CountDownLatch(1);
   4842                 mBackupLatch = new CountDownLatch(1);
   4843                 mPreflightResult = BackupTransport.AGENT_ERROR;
   4844                 mBackupResult = BackupTransport.AGENT_ERROR;
   4845             }
   4846 
   4847             @Override
   4848             public void run() {
   4849                 FileOutputStream out = new FileOutputStream(mOutput.getFileDescriptor());
   4850                 mEngine = new FullBackupEngine(out, mPreflight, mTarget, false, this);
   4851                 try {
   4852                     try {
   4853                         mPreflightResult = mEngine.preflightCheck();
   4854                     } finally {
   4855                         mPreflightLatch.countDown();
   4856                     }
   4857                     // If there is no error on preflight, continue backup.
   4858                     if (mPreflightResult == BackupTransport.TRANSPORT_OK) {
   4859                         mBackupResult = mEngine.backupOnePackage();
   4860                     }
   4861                 } catch (Exception e) {
   4862                     Slog.e(TAG, "Exception during full package backup of " + mTarget.packageName);
   4863                 } finally {
   4864                     mBackupLatch.countDown();
   4865                     try {
   4866                         mOutput.close();
   4867                     } catch (IOException e) {
   4868                         Slog.w(TAG, "Error closing transport pipe in runner");
   4869                     }
   4870                 }
   4871             }
   4872 
   4873             public void sendQuotaExceeded(final long backupDataBytes, final long quotaBytes) {
   4874                 mEngine.sendQuotaExceeded(backupDataBytes, quotaBytes);
   4875             }
   4876 
   4877             // If preflight succeeded, returns positive number - preflight size,
   4878             // otherwise return negative error code.
   4879             long getPreflightResultBlocking() {
   4880                 try {
   4881                     mPreflightLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS);
   4882                     if (mPreflightResult == BackupTransport.TRANSPORT_OK) {
   4883                         return mPreflight.getExpectedSizeOrErrorCode();
   4884                     } else {
   4885                         return mPreflightResult;
   4886                     }
   4887                 } catch (InterruptedException e) {
   4888                     return BackupTransport.AGENT_ERROR;
   4889                 }
   4890             }
   4891 
   4892             int getBackupResultBlocking() {
   4893                 try {
   4894                     mBackupLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS);
   4895                     return mBackupResult;
   4896                 } catch (InterruptedException e) {
   4897                     return BackupTransport.AGENT_ERROR;
   4898                 }
   4899             }
   4900 
   4901 
   4902             // BackupRestoreTask interface: specifically, timeout detection
   4903 
   4904             @Override
   4905             public void execute() { /* intentionally empty */ }
   4906 
   4907             @Override
   4908             public void operationComplete(long result) { /* intentionally empty */ }
   4909 
   4910             @Override
   4911             public void handleTimeout() {
   4912                 if (DEBUG) {
   4913                     Slog.w(TAG, "Full backup timeout of " + mTarget.packageName);
   4914                 }
   4915                 tearDownAgentAndKill(mTarget.applicationInfo);
   4916             }
   4917         }
   4918     }
   4919 
   4920     // ----- Full-data backup scheduling -----
   4921 
   4922     /**
   4923      * Schedule a job to tell us when it's a good time to run a full backup
   4924      */
   4925     void scheduleNextFullBackupJob(long transportMinLatency) {
   4926         synchronized (mQueueLock) {
   4927             if (mFullBackupQueue.size() > 0) {
   4928                 // schedule the next job at the point in the future when the least-recently
   4929                 // backed up app comes due for backup again; or immediately if it's already
   4930                 // due.
   4931                 final long upcomingLastBackup = mFullBackupQueue.get(0).lastBackup;
   4932                 final long timeSinceLast = System.currentTimeMillis() - upcomingLastBackup;
   4933                 final long appLatency = (timeSinceLast < MIN_FULL_BACKUP_INTERVAL)
   4934                         ? (MIN_FULL_BACKUP_INTERVAL - timeSinceLast) : 0;
   4935                 final long latency = Math.max(transportMinLatency, appLatency);
   4936                 Runnable r = new Runnable() {
   4937                     @Override public void run() {
   4938                         FullBackupJob.schedule(mContext, latency);
   4939                     }
   4940                 };
   4941                 mBackupHandler.postDelayed(r, 2500);
   4942             } else {
   4943                 if (DEBUG_SCHEDULING) {
   4944                     Slog.i(TAG, "Full backup queue empty; not scheduling");
   4945                 }
   4946             }
   4947         }
   4948     }
   4949 
   4950     /**
   4951      * Remove a package from the full-data queue.
   4952      */
   4953     void dequeueFullBackupLocked(String packageName) {
   4954         final int N = mFullBackupQueue.size();
   4955         for (int i = N-1; i >= 0; i--) {
   4956             final FullBackupEntry e = mFullBackupQueue.get(i);
   4957             if (packageName.equals(e.packageName)) {
   4958                 mFullBackupQueue.remove(i);
   4959             }
   4960         }
   4961     }
   4962 
   4963     /**
   4964      * Enqueue full backup for the given app, with a note about when it last ran.
   4965      */
   4966     void enqueueFullBackup(String packageName, long lastBackedUp) {
   4967         FullBackupEntry newEntry = new FullBackupEntry(packageName, lastBackedUp);
   4968         synchronized (mQueueLock) {
   4969             // First, sanity check that we aren't adding a duplicate.  Slow but
   4970             // straightforward; we'll have at most on the order of a few hundred
   4971             // items in this list.
   4972             dequeueFullBackupLocked(packageName);
   4973 
   4974             // This is also slow but easy for modest numbers of apps: work backwards
   4975             // from the end of the queue until we find an item whose last backup
   4976             // time was before this one, then insert this new entry after it.  If we're
   4977             // adding something new we don't bother scanning, and just prepend.
   4978             int which = -1;
   4979             if (lastBackedUp > 0) {
   4980                 for (which = mFullBackupQueue.size() - 1; which >= 0; which--) {
   4981                     final FullBackupEntry entry = mFullBackupQueue.get(which);
   4982                     if (entry.lastBackup <= lastBackedUp) {
   4983                         mFullBackupQueue.add(which + 1, newEntry);
   4984                         break;
   4985                     }
   4986                 }
   4987             }
   4988             if (which < 0) {
   4989                 // this one is earlier than any existing one, so prepend
   4990                 mFullBackupQueue.add(0, newEntry);
   4991             }
   4992         }
   4993         writeFullBackupScheduleAsync();
   4994     }
   4995 
   4996     private boolean fullBackupAllowable(IBackupTransport transport) {
   4997         if (transport == null) {
   4998             Slog.w(TAG, "Transport not present; full data backup not performed");
   4999             return false;
   5000         }
   5001 
   5002         // Don't proceed unless we have already established package metadata
   5003         // for the current dataset via a key/value backup pass.
   5004         try {
   5005             File stateDir = new File(mBaseStateDir, transport.transportDirName());
   5006             File pmState = new File(stateDir, PACKAGE_MANAGER_SENTINEL);
   5007             if (pmState.length() <= 0) {
   5008                 if (DEBUG) {
   5009                     Slog.i(TAG, "Full backup requested but dataset not yet initialized");
   5010                 }
   5011                 return false;
   5012             }
   5013         } catch (Exception e) {
   5014             Slog.w(TAG, "Unable to get transport name: " + e.getMessage());
   5015             return false;
   5016         }
   5017 
   5018         return true;
   5019     }
   5020 
   5021     /**
   5022      * Conditions are right for a full backup operation, so run one.  The model we use is
   5023      * to perform one app backup per scheduled job execution, and to reschedule the job
   5024      * with zero latency as long as conditions remain right and we still have work to do.
   5025      *
   5026      * <p>This is the "start a full backup operation" entry point called by the scheduled job.
   5027      *
   5028      * @return Whether ongoing work will continue.  The return value here will be passed
   5029      *         along as the return value to the scheduled job's onStartJob() callback.
   5030      */
   5031     boolean beginFullBackup(FullBackupJob scheduledJob) {
   5032         long now = System.currentTimeMillis();
   5033         FullBackupEntry entry = null;
   5034         long latency = MIN_FULL_BACKUP_INTERVAL;
   5035 
   5036         if (!mEnabled || !mProvisioned) {
   5037             // Backups are globally disabled, so don't proceed.  We also don't reschedule
   5038             // the job driving automatic backups; that job will be scheduled again when
   5039             // the user enables backup.
   5040             if (MORE_DEBUG) {
   5041                 Slog.i(TAG, "beginFullBackup but e=" + mEnabled
   5042                         + " p=" + mProvisioned + "; ignoring");
   5043             }
   5044             return false;
   5045         }
   5046 
   5047         // Don't run the backup if we're in battery saver mode, but reschedule
   5048         // to try again in the not-so-distant future.
   5049         if (mPowerManager.isPowerSaveMode()) {
   5050             if (DEBUG) Slog.i(TAG, "Deferring scheduled full backups in battery saver mode");
   5051             FullBackupJob.schedule(mContext, KeyValueBackupJob.BATCH_INTERVAL);
   5052             return false;
   5053         }
   5054 
   5055         if (DEBUG_SCHEDULING) {
   5056             Slog.i(TAG, "Beginning scheduled full backup operation");
   5057         }
   5058 
   5059         // Great; we're able to run full backup jobs now.  See if we have any work to do.
   5060         synchronized (mQueueLock) {
   5061             if (mRunningFullBackupTask != null) {
   5062                 Slog.e(TAG, "Backup triggered but one already/still running!");
   5063                 return false;
   5064             }
   5065 
   5066             // At this point we think that we have work to do, but possibly not right now.
   5067             // Any exit without actually running backups will also require that we
   5068             // reschedule the job.
   5069             boolean runBackup = true;
   5070             boolean headBusy;
   5071 
   5072             do {
   5073                 // Recheck each time, because culling due to ineligibility may
   5074                 // have emptied the queue.
   5075                 if (mFullBackupQueue.size() == 0) {
   5076                     // no work to do so just bow out
   5077                     if (DEBUG) {
   5078                         Slog.i(TAG, "Backup queue empty; doing nothing");
   5079                     }
   5080                     runBackup = false;
   5081                     break;
   5082                 }
   5083 
   5084                 headBusy = false;
   5085 
   5086                 if (!fullBackupAllowable(getTransport(mCurrentTransport))) {
   5087                     if (MORE_DEBUG) {
   5088                         Slog.i(TAG, "Preconditions not met; not running full backup");
   5089                     }
   5090                     runBackup = false;
   5091                     // Typically this means we haven't run a key/value backup yet.  Back off
   5092                     // full-backup operations by the key/value job's run interval so that
   5093                     // next time we run, we are likely to be able to make progress.
   5094                     latency = KeyValueBackupJob.BATCH_INTERVAL;
   5095                 }
   5096 
   5097                 if (runBackup) {
   5098                     entry = mFullBackupQueue.get(0);
   5099                     long timeSinceRun = now - entry.lastBackup;
   5100                     runBackup = (timeSinceRun >= MIN_FULL_BACKUP_INTERVAL);
   5101                     if (!runBackup) {
   5102                         // It's too early to back up the next thing in the queue, so bow out
   5103                         if (MORE_DEBUG) {
   5104                             Slog.i(TAG, "Device ready but too early to back up next app");
   5105                         }
   5106                         // Wait until the next app in the queue falls due for a full data backup
   5107                         latency = MIN_FULL_BACKUP_INTERVAL - timeSinceRun;
   5108                         break;  // we know we aren't doing work yet, so bail.
   5109                     }
   5110 
   5111                     try {
   5112                         PackageInfo appInfo = mPackageManager.getPackageInfo(entry.packageName, 0);
   5113                         if (!appGetsFullBackup(appInfo)) {
   5114                             // The head app isn't supposed to get full-data backups [any more];
   5115                             // so we cull it and force a loop around to consider the new head
   5116                             // app.
   5117                             if (MORE_DEBUG) {
   5118                                 Slog.i(TAG, "Culling package " + entry.packageName
   5119                                         + " in full-backup queue but not eligible");
   5120                             }
   5121                             mFullBackupQueue.remove(0);
   5122                             headBusy = true; // force the while() condition
   5123                             continue;
   5124                         }
   5125 
   5126                         final int privFlags = appInfo.applicationInfo.privateFlags;
   5127                         headBusy = (privFlags & PRIVATE_FLAG_BACKUP_IN_FOREGROUND) == 0
   5128                                 && mActivityManager.isAppForeground(appInfo.applicationInfo.uid);
   5129 
   5130                         if (headBusy) {
   5131                             final long nextEligible = System.currentTimeMillis()
   5132                                     + BUSY_BACKOFF_MIN_MILLIS
   5133                                     + mTokenGenerator.nextInt(BUSY_BACKOFF_FUZZ);
   5134                             if (DEBUG_SCHEDULING) {
   5135                                 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
   5136                                 Slog.i(TAG, "Full backup time but " + entry.packageName
   5137                                         + " is busy; deferring to "
   5138                                         + sdf.format(new Date(nextEligible)));
   5139                             }
   5140                             // This relocates the app's entry from the head of the queue to
   5141                             // its order-appropriate position further down, so upon looping
   5142                             // a new candidate will be considered at the head.
   5143                             enqueueFullBackup(entry.packageName,
   5144                                     nextEligible - MIN_FULL_BACKUP_INTERVAL);
   5145                         }
   5146                     } catch (NameNotFoundException nnf) {
   5147                         // So, we think we want to back this up, but it turns out the package
   5148                         // in question is no longer installed.  We want to drop it from the
   5149                         // queue entirely and move on, but if there's nothing else in the queue
   5150                         // we should bail entirely.  headBusy cannot have been set to true yet.
   5151                         runBackup = (mFullBackupQueue.size() > 1);
   5152                     } catch (RemoteException e) {
   5153                         // Cannot happen; the Activity Manager is in the same process
   5154                     }
   5155                 }
   5156             } while (headBusy);
   5157 
   5158             if (!runBackup) {
   5159                 if (DEBUG_SCHEDULING) {
   5160                     Slog.i(TAG, "Nothing pending full backup; rescheduling +" + latency);
   5161                 }
   5162                 final long deferTime = latency;     // pin for the closure
   5163                 mBackupHandler.post(new Runnable() {
   5164                     @Override public void run() {
   5165                         FullBackupJob.schedule(mContext, deferTime);
   5166                     }
   5167                 });
   5168                 return false;
   5169             }
   5170 
   5171             // Okay, the top thing is ready for backup now.  Do it.
   5172             mFullBackupQueue.remove(0);
   5173             CountDownLatch latch = new CountDownLatch(1);
   5174             String[] pkg = new String[] {entry.packageName};
   5175             mRunningFullBackupTask = new PerformFullTransportBackupTask(null, pkg, true,
   5176                     scheduledJob, latch, null, false /* userInitiated */);
   5177             // Acquiring wakelock for PerformFullTransportBackupTask before its start.
   5178             mWakelock.acquire();
   5179             (new Thread(mRunningFullBackupTask)).start();
   5180         }
   5181 
   5182         return true;
   5183     }
   5184 
   5185     // The job scheduler says our constraints don't hold any more,
   5186     // so tear down any ongoing backup task right away.
   5187     void endFullBackup() {
   5188         synchronized (mQueueLock) {
   5189             if (mRunningFullBackupTask != null) {
   5190                 if (DEBUG_SCHEDULING) {
   5191                     Slog.i(TAG, "Telling running backup to stop");
   5192                 }
   5193                 mRunningFullBackupTask.setRunning(false);
   5194             }
   5195         }
   5196     }
   5197 
   5198     // ----- Restore infrastructure -----
   5199 
   5200     abstract class RestoreEngine {
   5201         static final String TAG = "RestoreEngine";
   5202 
   5203         public static final int SUCCESS = 0;
   5204         public static final int TARGET_FAILURE = -2;
   5205         public static final int TRANSPORT_FAILURE = -3;
   5206 
   5207         private AtomicBoolean mRunning = new AtomicBoolean(false);
   5208         private AtomicInteger mResult = new AtomicInteger(SUCCESS);
   5209 
   5210         public boolean isRunning() {
   5211             return mRunning.get();
   5212         }
   5213 
   5214         public void setRunning(boolean stillRunning) {
   5215             synchronized (mRunning) {
   5216                 mRunning.set(stillRunning);
   5217                 mRunning.notifyAll();
   5218             }
   5219         }
   5220 
   5221         public int waitForResult() {
   5222             synchronized (mRunning) {
   5223                 while (isRunning()) {
   5224                     try {
   5225                         mRunning.wait();
   5226                     } catch (InterruptedException e) {}
   5227                 }
   5228             }
   5229             return getResult();
   5230         }
   5231 
   5232         public int getResult() {
   5233             return mResult.get();
   5234         }
   5235 
   5236         public void setResult(int result) {
   5237             mResult.set(result);
   5238         }
   5239 
   5240         // TODO: abstract restore state and APIs
   5241     }
   5242 
   5243     // ----- Full restore from a file/socket -----
   5244 
   5245     // Description of a file in the restore datastream
   5246     static class FileMetadata {
   5247         String packageName;             // name of the owning app
   5248         String installerPackageName;    // name of the market-type app that installed the owner
   5249         int type;                       // e.g. BackupAgent.TYPE_DIRECTORY
   5250         String domain;                  // e.g. FullBackup.DATABASE_TREE_TOKEN
   5251         String path;                    // subpath within the semantic domain
   5252         long mode;                      // e.g. 0666 (actually int)
   5253         long mtime;                     // last mod time, UTC time_t (actually int)
   5254         long size;                      // bytes of content
   5255 
   5256         @Override
   5257         public String toString() {
   5258             StringBuilder sb = new StringBuilder(128);
   5259             sb.append("FileMetadata{");
   5260             sb.append(packageName); sb.append(',');
   5261             sb.append(type); sb.append(',');
   5262             sb.append(domain); sb.append(':'); sb.append(path); sb.append(',');
   5263             sb.append(size);
   5264             sb.append('}');
   5265             return sb.toString();
   5266         }
   5267     }
   5268 
   5269     enum RestorePolicy {
   5270         IGNORE,
   5271         ACCEPT,
   5272         ACCEPT_IF_APK
   5273     }
   5274 
   5275     // Full restore engine, used by both adb restore and transport-based full restore
   5276     class FullRestoreEngine extends RestoreEngine {
   5277         // Task in charge of monitoring timeouts
   5278         BackupRestoreTask mMonitorTask;
   5279 
   5280         // Dedicated observer, if any
   5281         IFullBackupRestoreObserver mObserver;
   5282 
   5283         // Where we're delivering the file data as we go
   5284         IBackupAgent mAgent;
   5285 
   5286         // Are we permitted to only deliver a specific package's metadata?
   5287         PackageInfo mOnlyPackage;
   5288 
   5289         boolean mAllowApks;
   5290         boolean mAllowObbs;
   5291 
   5292         // Which package are we currently handling data for?
   5293         String mAgentPackage;
   5294 
   5295         // Info for working with the target app process
   5296         ApplicationInfo mTargetApp;
   5297 
   5298         // Machinery for restoring OBBs
   5299         FullBackupObbConnection mObbConnection = null;
   5300 
   5301         // possible handling states for a given package in the restore dataset
   5302         final HashMap<String, RestorePolicy> mPackagePolicies
   5303                 = new HashMap<String, RestorePolicy>();
   5304 
   5305         // installer package names for each encountered app, derived from the manifests
   5306         final HashMap<String, String> mPackageInstallers = new HashMap<String, String>();
   5307 
   5308         // Signatures for a given package found in its manifest file
   5309         final HashMap<String, Signature[]> mManifestSignatures
   5310                 = new HashMap<String, Signature[]>();
   5311 
   5312         // Packages we've already wiped data on when restoring their first file
   5313         final HashSet<String> mClearedPackages = new HashSet<String>();
   5314 
   5315         // How much data have we moved?
   5316         long mBytes;
   5317 
   5318         // Working buffer
   5319         byte[] mBuffer;
   5320 
   5321         // Pipes for moving data
   5322         ParcelFileDescriptor[] mPipes = null;
   5323 
   5324         // Widget blob to be restored out-of-band
   5325         byte[] mWidgetData = null;
   5326 
   5327         // Runner that can be placed in a separate thread to do in-process
   5328         // invocations of the full restore API asynchronously. Used by adb restore.
   5329         class RestoreFileRunnable implements Runnable {
   5330             IBackupAgent mAgent;
   5331             FileMetadata mInfo;
   5332             ParcelFileDescriptor mSocket;
   5333             int mToken;
   5334 
   5335             RestoreFileRunnable(IBackupAgent agent, FileMetadata info,
   5336                     ParcelFileDescriptor socket, int token) throws IOException {
   5337                 mAgent = agent;
   5338                 mInfo = info;
   5339                 mToken = token;
   5340 
   5341                 // This class is used strictly for process-local binder invocations.  The
   5342                 // semantics of ParcelFileDescriptor differ in this case; in particular, we
   5343                 // do not automatically get a 'dup'ed descriptor that we can can continue
   5344                 // to use asynchronously from the caller.  So, we make sure to dup it ourselves
   5345                 // before proceeding to do the restore.
   5346                 mSocket = ParcelFileDescriptor.dup(socket.getFileDescriptor());
   5347             }
   5348 
   5349             @Override
   5350             public void run() {
   5351                 try {
   5352                     mAgent.doRestoreFile(mSocket, mInfo.size, mInfo.type,
   5353                             mInfo.domain, mInfo.path, mInfo.mode, mInfo.mtime,
   5354                             mToken, mBackupManagerBinder);
   5355                 } catch (RemoteException e) {
   5356                     // never happens; this is used strictly for local binder calls
   5357                 }
   5358             }
   5359         }
   5360 
   5361         public FullRestoreEngine(BackupRestoreTask monitorTask, IFullBackupRestoreObserver observer,
   5362                 PackageInfo onlyPackage, boolean allowApks, boolean allowObbs) {
   5363             mMonitorTask = monitorTask;
   5364             mObserver = observer;
   5365             mOnlyPackage = onlyPackage;
   5366             mAllowApks = allowApks;
   5367             mAllowObbs = allowObbs;
   5368             mBuffer = new byte[32 * 1024];
   5369             mBytes = 0;
   5370         }
   5371 
   5372         public IBackupAgent getAgent() {
   5373             return mAgent;
   5374         }
   5375 
   5376         public byte[] getWidgetData() {
   5377             return mWidgetData;
   5378         }
   5379 
   5380         public boolean restoreOneFile(InputStream instream, boolean mustKillAgent) {
   5381             if (!isRunning()) {
   5382                 Slog.w(TAG, "Restore engine used after halting");
   5383                 return false;
   5384             }
   5385 
   5386             FileMetadata info;
   5387             try {
   5388                 if (MORE_DEBUG) {
   5389                     Slog.v(TAG, "Reading tar header for restoring file");
   5390                 }
   5391                 info = readTarHeaders(instream);
   5392                 if (info != null) {
   5393                     if (MORE_DEBUG) {
   5394                         dumpFileMetadata(info);
   5395                     }
   5396 
   5397                     final String pkg = info.packageName;
   5398                     if (!pkg.equals(mAgentPackage)) {
   5399                         // In the single-package case, it's a semantic error to expect
   5400                         // one app's data but see a different app's on the wire
   5401                         if (mOnlyPackage != null) {
   5402                             if (!pkg.equals(mOnlyPackage.packageName)) {
   5403                                 Slog.w(TAG, "Expected data for " + mOnlyPackage
   5404                                         + " but saw " + pkg);
   5405                                 setResult(RestoreEngine.TRANSPORT_FAILURE);
   5406                                 setRunning(false);
   5407                                 return false;
   5408                             }
   5409                         }
   5410 
   5411                         // okay, change in package; set up our various
   5412                         // bookkeeping if we haven't seen it yet
   5413                         if (!mPackagePolicies.containsKey(pkg)) {
   5414                             mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
   5415                         }
   5416 
   5417                         // Clean up the previous agent relationship if necessary,
   5418                         // and let the observer know we're considering a new app.
   5419                         if (mAgent != null) {
   5420                             if (DEBUG) Slog.d(TAG, "Saw new package; finalizing old one");
   5421                             // Now we're really done
   5422                             tearDownPipes();
   5423                             tearDownAgent(mTargetApp);
   5424                             mTargetApp = null;
   5425                             mAgentPackage = null;
   5426                         }
   5427                     }
   5428 
   5429                     if (info.path.equals(BACKUP_MANIFEST_FILENAME)) {
   5430                         mPackagePolicies.put(pkg, readAppManifest(info, instream));
   5431                         mPackageInstallers.put(pkg, info.installerPackageName);
   5432                         // We've read only the manifest content itself at this point,
   5433                         // so consume the footer before looping around to the next
   5434                         // input file
   5435                         skipTarPadding(info.size, instream);
   5436                         sendOnRestorePackage(pkg);
   5437                     } else if (info.path.equals(BACKUP_METADATA_FILENAME)) {
   5438                         // Metadata blobs!
   5439                         readMetadata(info, instream);
   5440                         skipTarPadding(info.size, instream);
   5441                     } else {
   5442                         // Non-manifest, so it's actual file data.  Is this a package
   5443                         // we're ignoring?
   5444                         boolean okay = true;
   5445                         RestorePolicy policy = mPackagePolicies.get(pkg);
   5446                         switch (policy) {
   5447                             case IGNORE:
   5448                                 okay = false;
   5449                                 break;
   5450 
   5451                             case ACCEPT_IF_APK:
   5452                                 // If we're in accept-if-apk state, then the first file we
   5453                                 // see MUST be the apk.
   5454                                 if (info.domain.equals(FullBackup.APK_TREE_TOKEN)) {
   5455                                     if (DEBUG) Slog.d(TAG, "APK file; installing");
   5456                                     // Try to install the app.
   5457                                     String installerName = mPackageInstallers.get(pkg);
   5458                                     okay = installApk(info, installerName, instream);
   5459                                     // good to go; promote to ACCEPT
   5460                                     mPackagePolicies.put(pkg, (okay)
   5461                                             ? RestorePolicy.ACCEPT
   5462                                                     : RestorePolicy.IGNORE);
   5463                                     // At this point we've consumed this file entry
   5464                                     // ourselves, so just strip the tar footer and
   5465                                     // go on to the next file in the input stream
   5466                                     skipTarPadding(info.size, instream);
   5467                                     return true;
   5468                                 } else {
   5469                                     // File data before (or without) the apk.  We can't
   5470                                     // handle it coherently in this case so ignore it.
   5471                                     mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
   5472                                     okay = false;
   5473                                 }
   5474                                 break;
   5475 
   5476                             case ACCEPT:
   5477                                 if (info.domain.equals(FullBackup.APK_TREE_TOKEN)) {
   5478                                     if (DEBUG) Slog.d(TAG, "apk present but ACCEPT");
   5479                                     // we can take the data without the apk, so we
   5480                                     // *want* to do so.  skip the apk by declaring this
   5481                                     // one file not-okay without changing the restore
   5482                                     // policy for the package.
   5483                                     okay = false;
   5484                                 }
   5485                                 break;
   5486 
   5487                             default:
   5488                                 // Something has gone dreadfully wrong when determining
   5489                                 // the restore policy from the manifest.  Ignore the
   5490                                 // rest of this package's data.
   5491                                 Slog.e(TAG, "Invalid policy from manifest");
   5492                                 okay = false;
   5493                                 mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
   5494                                 break;
   5495                         }
   5496 
   5497                         // Is it a *file* we need to drop?
   5498                         if (!isRestorableFile(info)) {
   5499                             okay = false;
   5500                         }
   5501 
   5502                         // If the policy is satisfied, go ahead and set up to pipe the
   5503                         // data to the agent.
   5504                         if (MORE_DEBUG && okay && mAgent != null) {
   5505                             Slog.i(TAG, "Reusing existing agent instance");
   5506                         }
   5507                         if (okay && mAgent == null) {
   5508                             if (MORE_DEBUG) Slog.d(TAG, "Need to launch agent for " + pkg);
   5509 
   5510                             try {
   5511                                 mTargetApp = mPackageManager.getApplicationInfo(pkg, 0);
   5512 
   5513                                 // If we haven't sent any data to this app yet, we probably
   5514                                 // need to clear it first.  Check that.
   5515                                 if (!mClearedPackages.contains(pkg)) {
   5516                                     // apps with their own backup agents are
   5517                                     // responsible for coherently managing a full
   5518                                     // restore.
   5519                                     if (mTargetApp.backupAgentName == null) {
   5520                                         if (DEBUG) Slog.d(TAG, "Clearing app data preparatory to full restore");
   5521                                         clearApplicationDataSynchronous(pkg);
   5522                                     } else {
   5523                                         if (MORE_DEBUG) Slog.d(TAG, "backup agent ("
   5524                                                 + mTargetApp.backupAgentName + ") => no clear");
   5525                                     }
   5526                                     mClearedPackages.add(pkg);
   5527                                 } else {
   5528                                     if (MORE_DEBUG) {
   5529                                         Slog.d(TAG, "We've initialized this app already; no clear required");
   5530                                     }
   5531                                 }
   5532 
   5533                                 // All set; now set up the IPC and launch the agent
   5534                                 setUpPipes();
   5535                                 mAgent = bindToAgentSynchronous(mTargetApp,
   5536                                         IApplicationThread.BACKUP_MODE_RESTORE_FULL);
   5537                                 mAgentPackage = pkg;
   5538                             } catch (IOException e) {
   5539                                 // fall through to error handling
   5540                             } catch (NameNotFoundException e) {
   5541                                 // fall through to error handling
   5542                             }
   5543 
   5544                             if (mAgent == null) {
   5545                                 Slog.e(TAG, "Unable to create agent for " + pkg);
   5546                                 okay = false;
   5547                                 tearDownPipes();
   5548                                 mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
   5549                             }
   5550                         }
   5551 
   5552                         // Sanity check: make sure we never give data to the wrong app.  This
   5553                         // should never happen but a little paranoia here won't go amiss.
   5554                         if (okay && !pkg.equals(mAgentPackage)) {
   5555                             Slog.e(TAG, "Restoring data for " + pkg
   5556                                     + " but agent is for " + mAgentPackage);
   5557                             okay = false;
   5558                         }
   5559 
   5560                         // At this point we have an agent ready to handle the full
   5561                         // restore data as well as a pipe for sending data to
   5562                         // that agent.  Tell the agent to start reading from the
   5563                         // pipe.
   5564                         if (okay) {
   5565                             boolean agentSuccess = true;
   5566                             long toCopy = info.size;
   5567                             final int token = generateToken();
   5568                             try {
   5569                                 prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL,
   5570                                         mMonitorTask);
   5571 
   5572                                 if (info.domain.equals(FullBackup.OBB_TREE_TOKEN)) {
   5573                                     if (DEBUG) Slog.d(TAG, "Restoring OBB file for " + pkg
   5574                                             + " : " + info.path);
   5575                                     mObbConnection.restoreObbFile(pkg, mPipes[0],
   5576                                             info.size, info.type, info.path, info.mode,
   5577                                             info.mtime, token, mBackupManagerBinder);
   5578                                 } else {
   5579                                     if (MORE_DEBUG) Slog.d(TAG, "Invoking agent to restore file "
   5580                                             + info.path);
   5581                                     // fire up the app's agent listening on the socket.  If
   5582                                     // the agent is running in the system process we can't
   5583                                     // just invoke it asynchronously, so we provide a thread
   5584                                     // for it here.
   5585                                     if (mTargetApp.processName.equals("system")) {
   5586                                         Slog.d(TAG, "system process agent - spinning a thread");
   5587                                         RestoreFileRunnable runner = new RestoreFileRunnable(
   5588                                                 mAgent, info, mPipes[0], token);
   5589                                         new Thread(runner, "restore-sys-runner").start();
   5590                                     } else {
   5591                                         mAgent.doRestoreFile(mPipes[0], info.size, info.type,
   5592                                                 info.domain, info.path, info.mode, info.mtime,
   5593                                                 token, mBackupManagerBinder);
   5594                                     }
   5595                                 }
   5596                             } catch (IOException e) {
   5597                                 // couldn't dup the socket for a process-local restore
   5598                                 Slog.d(TAG, "Couldn't establish restore");
   5599                                 agentSuccess = false;
   5600                                 okay = false;
   5601                             } catch (RemoteException e) {
   5602                                 // whoops, remote entity went away.  We'll eat the content
   5603                                 // ourselves, then, and not copy it over.
   5604                                 Slog.e(TAG, "Agent crashed during full restore");
   5605                                 agentSuccess = false;
   5606                                 okay = false;
   5607                             }
   5608 
   5609                             // Copy over the data if the agent is still good
   5610                             if (okay) {
   5611                                 if (MORE_DEBUG) {
   5612                                     Slog.v(TAG, "  copying to restore agent: "
   5613                                             + toCopy + " bytes");
   5614                                 }
   5615                                 boolean pipeOkay = true;
   5616                                 FileOutputStream pipe = new FileOutputStream(
   5617                                         mPipes[1].getFileDescriptor());
   5618                                 while (toCopy > 0) {
   5619                                     int toRead = (toCopy > mBuffer.length)
   5620                                             ? mBuffer.length : (int)toCopy;
   5621                                     int nRead = instream.read(mBuffer, 0, toRead);
   5622                                     if (nRead >= 0) mBytes += nRead;
   5623                                     if (nRead <= 0) break;
   5624                                     toCopy -= nRead;
   5625 
   5626                                     // send it to the output pipe as long as things
   5627                                     // are still good
   5628                                     if (pipeOkay) {
   5629                                         try {
   5630                                             pipe.write(mBuffer, 0, nRead);
   5631                                         } catch (IOException e) {
   5632                                             Slog.e(TAG, "Failed to write to restore pipe: "
   5633                                                     + e.getMessage());
   5634                                             pipeOkay = false;
   5635                                         }
   5636                                     }
   5637                                 }
   5638 
   5639                                 // done sending that file!  Now we just need to consume
   5640                                 // the delta from info.size to the end of block.
   5641                                 skipTarPadding(info.size, instream);
   5642 
   5643                                 // and now that we've sent it all, wait for the remote
   5644                                 // side to acknowledge receipt
   5645                                 agentSuccess = waitUntilOperationComplete(token);
   5646                             }
   5647 
   5648                             // okay, if the remote end failed at any point, deal with
   5649                             // it by ignoring the rest of the restore on it
   5650                             if (!agentSuccess) {
   5651                                 Slog.w(TAG, "Agent failure; ending restore");
   5652                                 mBackupHandler.removeMessages(MSG_TIMEOUT);
   5653                                 tearDownPipes();
   5654                                 tearDownAgent(mTargetApp);
   5655                                 mAgent = null;
   5656                                 mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
   5657 
   5658                                 // If this was a single-package restore, we halt immediately
   5659                                 // with an agent error under these circumstances
   5660                                 if (mOnlyPackage != null) {
   5661                                     setResult(RestoreEngine.TARGET_FAILURE);
   5662                                     setRunning(false);
   5663                                     return false;
   5664                                 }
   5665                             }
   5666                         }
   5667 
   5668                         // Problems setting up the agent communication, an explicitly
   5669                         // dropped file, or an already-ignored package: skip to the
   5670                         // next stream entry by reading and discarding this file.
   5671                         if (!okay) {
   5672                             if (MORE_DEBUG) Slog.d(TAG, "[discarding file content]");
   5673                             long bytesToConsume = (info.size + 511) & ~511;
   5674                             while (bytesToConsume > 0) {
   5675                                 int toRead = (bytesToConsume > mBuffer.length)
   5676                                         ? mBuffer.length : (int)bytesToConsume;
   5677                                 long nRead = instream.read(mBuffer, 0, toRead);
   5678                                 if (nRead >= 0) mBytes += nRead;
   5679                                 if (nRead <= 0) break;
   5680                                 bytesToConsume -= nRead;
   5681                             }
   5682                         }
   5683                     }
   5684                 }
   5685             } catch (IOException e) {
   5686                 if (DEBUG) Slog.w(TAG, "io exception on restore socket read: " + e.getMessage());
   5687                 setResult(RestoreEngine.TRANSPORT_FAILURE);
   5688                 info = null;
   5689             }
   5690 
   5691             // If we got here we're either running smoothly or we've finished
   5692             if (info == null) {
   5693                 if (MORE_DEBUG) {
   5694                     Slog.i(TAG, "No [more] data for this package; tearing down");
   5695                 }
   5696                 tearDownPipes();
   5697                 setRunning(false);
   5698                 if (mustKillAgent) {
   5699                     tearDownAgent(mTargetApp);
   5700                 }
   5701             }
   5702             return (info != null);
   5703         }
   5704 
   5705         void setUpPipes() throws IOException {
   5706             mPipes = ParcelFileDescriptor.createPipe();
   5707         }
   5708 
   5709         void tearDownPipes() {
   5710             // Teardown might arise from the inline restore processing or from the asynchronous
   5711             // timeout mechanism, and these might race.  Make sure we don't try to close and
   5712             // null out the pipes twice.
   5713             synchronized (this) {
   5714                 if (mPipes != null) {
   5715                     try {
   5716                         mPipes[0].close();
   5717                         mPipes[0] = null;
   5718                         mPipes[1].close();
   5719                         mPipes[1] = null;
   5720                     } catch (IOException e) {
   5721                         Slog.w(TAG, "Couldn't close agent pipes", e);
   5722                     }
   5723                     mPipes = null;
   5724                 }
   5725             }
   5726         }
   5727 
   5728         void tearDownAgent(ApplicationInfo app) {
   5729             if (mAgent != null) {
   5730                 tearDownAgentAndKill(app);
   5731                 mAgent = null;
   5732             }
   5733         }
   5734 
   5735         void handleTimeout() {
   5736             tearDownPipes();
   5737             setResult(RestoreEngine.TARGET_FAILURE);
   5738             setRunning(false);
   5739         }
   5740 
   5741         class RestoreInstallObserver extends PackageInstallObserver {
   5742             final AtomicBoolean mDone = new AtomicBoolean();
   5743             String mPackageName;
   5744             int mResult;
   5745 
   5746             public void reset() {
   5747                 synchronized (mDone) {
   5748                     mDone.set(false);
   5749                 }
   5750             }
   5751 
   5752             public void waitForCompletion() {
   5753                 synchronized (mDone) {
   5754                     while (mDone.get() == false) {
   5755                         try {
   5756                             mDone.wait();
   5757                         } catch (InterruptedException e) { }
   5758                     }
   5759                 }
   5760             }
   5761 
   5762             int getResult() {
   5763                 return mResult;
   5764             }
   5765 
   5766             @Override
   5767             public void onPackageInstalled(String packageName, int returnCode,
   5768                     String msg, Bundle extras) {
   5769                 synchronized (mDone) {
   5770                     mResult = returnCode;
   5771                     mPackageName = packageName;
   5772                     mDone.set(true);
   5773                     mDone.notifyAll();
   5774                 }
   5775             }
   5776         }
   5777 
   5778         class RestoreDeleteObserver extends IPackageDeleteObserver.Stub {
   5779             final AtomicBoolean mDone = new AtomicBoolean();
   5780             int mResult;
   5781 
   5782             public void reset() {
   5783                 synchronized (mDone) {
   5784                     mDone.set(false);
   5785                 }
   5786             }
   5787 
   5788             public void waitForCompletion() {
   5789                 synchronized (mDone) {
   5790                     while (mDone.get() == false) {
   5791                         try {
   5792                             mDone.wait();
   5793                         } catch (InterruptedException e) { }
   5794                     }
   5795                 }
   5796             }
   5797 
   5798             @Override
   5799             public void packageDeleted(String packageName, int returnCode) throws RemoteException {
   5800                 synchronized (mDone) {
   5801                     mResult = returnCode;
   5802                     mDone.set(true);
   5803                     mDone.notifyAll();
   5804                 }
   5805             }
   5806         }
   5807 
   5808         final RestoreInstallObserver mInstallObserver = new RestoreInstallObserver();
   5809         final RestoreDeleteObserver mDeleteObserver = new RestoreDeleteObserver();
   5810 
   5811         boolean installApk(FileMetadata info, String installerPackage, InputStream instream) {
   5812             boolean okay = true;
   5813 
   5814             if (DEBUG) Slog.d(TAG, "Installing from backup: " + info.packageName);
   5815 
   5816             // The file content is an .apk file.  Copy it out to a staging location and
   5817             // attempt to install it.
   5818             File apkFile = new File(mDataDir, info.packageName);
   5819             try {
   5820                 FileOutputStream apkStream = new FileOutputStream(apkFile);
   5821                 byte[] buffer = new byte[32 * 1024];
   5822                 long size = info.size;
   5823                 while (size > 0) {
   5824                     long toRead = (buffer.length < size) ? buffer.length : size;
   5825                     int didRead = instream.read(buffer, 0, (int)toRead);
   5826                     if (didRead >= 0) mBytes += didRead;
   5827                     apkStream.write(buffer, 0, didRead);
   5828                     size -= didRead;
   5829                 }
   5830                 apkStream.close();
   5831 
   5832                 // make sure the installer can read it
   5833                 apkFile.setReadable(true, false);
   5834 
   5835                 // Now install it
   5836                 Uri packageUri = Uri.fromFile(apkFile);
   5837                 mInstallObserver.reset();
   5838                 mPackageManager.installPackage(packageUri, mInstallObserver,
   5839                         PackageManager.INSTALL_REPLACE_EXISTING | PackageManager.INSTALL_FROM_ADB,
   5840                         installerPackage);
   5841                 mInstallObserver.waitForCompletion();
   5842 
   5843                 if (mInstallObserver.getResult() != PackageManager.INSTALL_SUCCEEDED) {
   5844                     // The only time we continue to accept install of data even if the
   5845                     // apk install failed is if we had already determined that we could
   5846                     // accept the data regardless.
   5847                     if (mPackagePolicies.get(info.packageName) != RestorePolicy.ACCEPT) {
   5848                         okay = false;
   5849                     }
   5850                 } else {
   5851                     // Okay, the install succeeded.  Make sure it was the right app.
   5852                     boolean uninstall = false;
   5853                     if (!mInstallObserver.mPackageName.equals(info.packageName)) {
   5854                         Slog.w(TAG, "Restore stream claimed to include apk for "
   5855                                 + info.packageName + " but apk was really "
   5856                                 + mInstallObserver.mPackageName);
   5857                         // delete the package we just put in place; it might be fraudulent
   5858                         okay = false;
   5859                         uninstall = true;
   5860                     } else {
   5861                         try {
   5862                             PackageInfo pkg = mPackageManager.getPackageInfo(info.packageName,
   5863                                     PackageManager.GET_SIGNATURES);
   5864                             if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) {
   5865                                 Slog.w(TAG, "Restore stream contains apk of package "
   5866                                         + info.packageName + " but it disallows backup/restore");
   5867                                 okay = false;
   5868                             } else {
   5869                                 // So far so good -- do the signatures match the manifest?
   5870                                 Signature[] sigs = mManifestSignatures.get(info.packageName);
   5871                                 if (signaturesMatch(sigs, pkg)) {
   5872                                     // If this is a system-uid app without a declared backup agent,
   5873                                     // don't restore any of the file data.
   5874                                     if ((pkg.applicationInfo.uid < Process.FIRST_APPLICATION_UID)
   5875                                             && (pkg.applicationInfo.backupAgentName == null)) {
   5876                                         Slog.w(TAG, "Installed app " + info.packageName
   5877                                                 + " has restricted uid and no agent");
   5878                                         okay = false;
   5879                                     }
   5880                                 } else {
   5881                                     Slog.w(TAG, "Installed app " + info.packageName
   5882                                             + " signatures do not match restore manifest");
   5883                                     okay = false;
   5884                                     uninstall = true;
   5885                                 }
   5886                             }
   5887                         } catch (NameNotFoundException e) {
   5888                             Slog.w(TAG, "Install of package " + info.packageName
   5889                                     + " succeeded but now not found");
   5890                             okay = false;
   5891                         }
   5892                     }
   5893 
   5894                     // If we're not okay at this point, we need to delete the package
   5895                     // that we just installed.
   5896                     if (uninstall) {
   5897                         mDeleteObserver.reset();
   5898                         mPackageManager.deletePackage(mInstallObserver.mPackageName,
   5899                                 mDeleteObserver, 0);
   5900                         mDeleteObserver.waitForCompletion();
   5901                     }
   5902                 }
   5903             } catch (IOException e) {
   5904                 Slog.e(TAG, "Unable to transcribe restored apk for install");
   5905                 okay = false;
   5906             } finally {
   5907                 apkFile.delete();
   5908             }
   5909 
   5910             return okay;
   5911         }
   5912 
   5913         // Given an actual file content size, consume the post-content padding mandated
   5914         // by the tar format.
   5915         void skipTarPadding(long size, InputStream instream) throws IOException {
   5916             long partial = (size + 512) % 512;
   5917             if (partial > 0) {
   5918                 final int needed = 512 - (int)partial;
   5919                 if (MORE_DEBUG) {
   5920                     Slog.i(TAG, "Skipping tar padding: " + needed + " bytes");
   5921                 }
   5922                 byte[] buffer = new byte[needed];
   5923                 if (readExactly(instream, buffer, 0, needed) == needed) {
   5924                     mBytes += needed;
   5925                 } else throw new IOException("Unexpected EOF in padding");
   5926             }
   5927         }
   5928 
   5929         // Read a widget metadata file, returning the restored blob
   5930         void readMetadata(FileMetadata info, InputStream instream) throws IOException {
   5931             // Fail on suspiciously large widget dump files
   5932             if (info.size > 64 * 1024) {
   5933                 throw new IOException("Metadata too big; corrupt? size=" + info.size);
   5934             }
   5935 
   5936             byte[] buffer = new byte[(int) info.size];
   5937             if (readExactly(instream, buffer, 0, (int)info.size) == info.size) {
   5938                 mBytes += info.size;
   5939             } else throw new IOException("Unexpected EOF in widget data");
   5940 
   5941             String[] str = new String[1];
   5942             int offset = extractLine(buffer, 0, str);
   5943             int version = Integer.parseInt(str[0]);
   5944             if (version == BACKUP_MANIFEST_VERSION) {
   5945                 offset = extractLine(buffer, offset, str);
   5946                 final String pkg = str[0];
   5947                 if (info.packageName.equals(pkg)) {
   5948                     // Data checks out -- the rest of the buffer is a concatenation of
   5949                     // binary blobs as described in the comment at writeAppWidgetData()
   5950                     ByteArrayInputStream bin = new ByteArrayInputStream(buffer,
   5951                             offset, buffer.length - offset);
   5952                     DataInputStream in = new DataInputStream(bin);
   5953                     while (bin.available() > 0) {
   5954                         int token = in.readInt();
   5955                         int size = in.readInt();
   5956                         if (size > 64 * 1024) {
   5957                             throw new IOException("Datum "
   5958                                     + Integer.toHexString(token)
   5959                                     + " too big; corrupt? size=" + info.size);
   5960                         }
   5961                         switch (token) {
   5962                             case BACKUP_WIDGET_METADATA_TOKEN:
   5963                             {
   5964                                 if (MORE_DEBUG) {
   5965                                     Slog.i(TAG, "Got widget metadata for " + info.packageName);
   5966                                 }
   5967                                 mWidgetData = new byte[size];
   5968                                 in.read(mWidgetData);
   5969                                 break;
   5970                             }
   5971                             default:
   5972                             {
   5973                                 if (DEBUG) {
   5974                                     Slog.i(TAG, "Ignoring metadata blob "
   5975                                             + Integer.toHexString(token)
   5976                                             + " for " + info.packageName);
   5977                                 }
   5978                                 in.skipBytes(size);
   5979                                 break;
   5980                             }
   5981                         }
   5982                     }
   5983                 } else {
   5984                     Slog.w(TAG, "Metadata mismatch: package " + info.packageName
   5985                             + " but widget data for " + pkg);
   5986                 }
   5987             } else {
   5988                 Slog.w(TAG, "Unsupported metadata version " + version);
   5989             }
   5990         }
   5991 
   5992         // Returns a policy constant
   5993         RestorePolicy readAppManifest(FileMetadata info, InputStream instream)
   5994                 throws IOException {
   5995             // Fail on suspiciously large manifest files
   5996             if (info.size > 64 * 1024) {
   5997                 throw new IOException("Restore manifest too big; corrupt? size=" + info.size);
   5998             }
   5999 
   6000             byte[] buffer = new byte[(int) info.size];
   6001             if (MORE_DEBUG) {
   6002                 Slog.i(TAG, "   readAppManifest() looking for " + info.size + " bytes, "
   6003                         + mBytes + " already consumed");
   6004             }
   6005             if (readExactly(instream, buffer, 0, (int)info.size) == info.size) {
   6006                 mBytes += info.size;
   6007             } else throw new IOException("Unexpected EOF in manifest");
   6008 
   6009             RestorePolicy policy = RestorePolicy.IGNORE;
   6010             String[] str = new String[1];
   6011             int offset = 0;
   6012 
   6013             try {
   6014                 offset = extractLine(buffer, offset, str);
   6015                 int version = Integer.parseInt(str[0]);
   6016                 if (version == BACKUP_MANIFEST_VERSION) {
   6017                     offset = extractLine(buffer, offset, str);
   6018                     String manifestPackage = str[0];
   6019                     // TODO: handle <original-package>
   6020                     if (manifestPackage.equals(info.packageName)) {
   6021                         offset = extractLine(buffer, offset, str);
   6022                         version = Integer.parseInt(str[0]);  // app version
   6023                         offset = extractLine(buffer, offset, str);
   6024                         // This is the platform version, which we don't use, but we parse it
   6025                         // as a safety against corruption in the manifest.
   6026                         Integer.parseInt(str[0]);
   6027                         offset = extractLine(buffer, offset, str);
   6028                         info.installerPackageName = (str[0].length() > 0) ? str[0] : null;
   6029                         offset = extractLine(buffer, offset, str);
   6030                         boolean hasApk = str[0].equals("1");
   6031                         offset = extractLine(buffer, offset, str);
   6032                         int numSigs = Integer.parseInt(str[0]);
   6033                         if (numSigs > 0) {
   6034                             Signature[] sigs = new Signature[numSigs];
   6035                             for (int i = 0; i < numSigs; i++) {
   6036                                 offset = extractLine(buffer, offset, str);
   6037                                 sigs[i] = new Signature(str[0]);
   6038                             }
   6039                             mManifestSignatures.put(info.packageName, sigs);
   6040 
   6041                             // Okay, got the manifest info we need...
   6042                             try {
   6043                                 PackageInfo pkgInfo = mPackageManager.getPackageInfo(
   6044                                         info.packageName, PackageManager.GET_SIGNATURES);
   6045                                 // Fall through to IGNORE if the app explicitly disallows backup
   6046                                 final int flags = pkgInfo.applicationInfo.flags;
   6047                                 if ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0) {
   6048                                     // Restore system-uid-space packages only if they have
   6049                                     // defined a custom backup agent
   6050                                     if ((pkgInfo.applicationInfo.uid >= Process.FIRST_APPLICATION_UID)
   6051                                             || (pkgInfo.applicationInfo.backupAgentName != null)) {
   6052                                         // Verify signatures against any installed version; if they
   6053                                         // don't match, then we fall though and ignore the data.  The
   6054                                         // signatureMatch() method explicitly ignores the signature
   6055                                         // check for packages installed on the system partition, because
   6056                                         // such packages are signed with the platform cert instead of
   6057                                         // the app developer's cert, so they're different on every
   6058                                         // device.
   6059                                         if (signaturesMatch(sigs, pkgInfo)) {
   6060                                             if ((pkgInfo.applicationInfo.flags
   6061                                                     & ApplicationInfo.FLAG_RESTORE_ANY_VERSION) != 0) {
   6062                                                 Slog.i(TAG, "Package has restoreAnyVersion; taking data");
   6063                                                 policy = RestorePolicy.ACCEPT;
   6064                                             } else if (pkgInfo.versionCode >= version) {
   6065                                                 Slog.i(TAG, "Sig + version match; taking data");
   6066                                                 policy = RestorePolicy.ACCEPT;
   6067                                             } else {
   6068                                                 // The data is from a newer version of the app than
   6069                                                 // is presently installed.  That means we can only
   6070                                                 // use it if the matching apk is also supplied.
   6071                                                 if (mAllowApks) {
   6072                                                     Slog.i(TAG, "Data version " + version
   6073                                                             + " is newer than installed version "
   6074                                                             + pkgInfo.versionCode
   6075                                                             + " - requiring apk");
   6076                                                     policy = RestorePolicy.ACCEPT_IF_APK;
   6077                                                 } else {
   6078                                                     Slog.i(TAG, "Data requires newer version "
   6079                                                             + version + "; ignoring");
   6080                                                     policy = RestorePolicy.IGNORE;
   6081                                                 }
   6082                                             }
   6083                                         } else {
   6084                                             Slog.w(TAG, "Restore manifest signatures do not match "
   6085                                                     + "installed application for " + info.packageName);
   6086                                         }
   6087                                     } else {
   6088                                         Slog.w(TAG, "Package " + info.packageName
   6089                                                 + " is system level with no agent");
   6090                                     }
   6091                                 } else {
   6092                                     if (DEBUG) Slog.i(TAG, "Restore manifest from "
   6093                                             + info.packageName + " but allowBackup=false");
   6094                                 }
   6095                             } catch (NameNotFoundException e) {
   6096                                 // Okay, the target app isn't installed.  We can process
   6097                                 // the restore properly only if the dataset provides the
   6098                                 // apk file and we can successfully install it.
   6099                                 if (mAllowApks) {
   6100                                     if (DEBUG) Slog.i(TAG, "Package " + info.packageName
   6101                                             + " not installed; requiring apk in dataset");
   6102                                     policy = RestorePolicy.ACCEPT_IF_APK;
   6103                                 } else {
   6104                                     policy = RestorePolicy.IGNORE;
   6105                                 }
   6106                             }
   6107 
   6108                             if (policy == RestorePolicy.ACCEPT_IF_APK && !hasApk) {
   6109                                 Slog.i(TAG, "Cannot restore package " + info.packageName
   6110                                         + " without the matching .apk");
   6111                             }
   6112                         } else {
   6113                             Slog.i(TAG, "Missing signature on backed-up package "
   6114                                     + info.packageName);
   6115                         }
   6116                     } else {
   6117                         Slog.i(TAG, "Expected package " + info.packageName
   6118                                 + " but restore manifest claims " + manifestPackage);
   6119                     }
   6120                 } else {
   6121                     Slog.i(TAG, "Unknown restore manifest version " + version
   6122                             + " for package " + info.packageName);
   6123                 }
   6124             } catch (NumberFormatException e) {
   6125                 Slog.w(TAG, "Corrupt restore manifest for package " + info.packageName);
   6126             } catch (IllegalArgumentException e) {
   6127                 Slog.w(TAG, e.getMessage());
   6128             }
   6129 
   6130             return policy;
   6131         }
   6132 
   6133         // Builds a line from a byte buffer starting at 'offset', and returns
   6134         // the index of the next unconsumed data in the buffer.
   6135         int extractLine(byte[] buffer, int offset, String[] outStr) throws IOException {
   6136             final int end = buffer.length;
   6137             if (offset >= end) throw new IOException("Incomplete data");
   6138 
   6139             int pos;
   6140             for (pos = offset; pos < end; pos++) {
   6141                 byte c = buffer[pos];
   6142                 // at LF we declare end of line, and return the next char as the
   6143                 // starting point for the next time through
   6144                 if (c == '\n') {
   6145                     break;
   6146                 }
   6147             }
   6148             outStr[0] = new String(buffer, offset, pos - offset);
   6149             pos++;  // may be pointing an extra byte past the end but that's okay
   6150             return pos;
   6151         }
   6152 
   6153         void dumpFileMetadata(FileMetadata info) {
   6154             if (MORE_DEBUG) {
   6155                 StringBuilder b = new StringBuilder(128);
   6156 
   6157                 // mode string
   6158                 b.append((info.type == BackupAgent.TYPE_DIRECTORY) ? 'd' : '-');
   6159                 b.append(((info.mode & 0400) != 0) ? 'r' : '-');
   6160                 b.append(((info.mode & 0200) != 0) ? 'w' : '-');
   6161                 b.append(((info.mode & 0100) != 0) ? 'x' : '-');
   6162                 b.append(((info.mode & 0040) != 0) ? 'r' : '-');
   6163                 b.append(((info.mode & 0020) != 0) ? 'w' : '-');
   6164                 b.append(((info.mode & 0010) != 0) ? 'x' : '-');
   6165                 b.append(((info.mode & 0004) != 0) ? 'r' : '-');
   6166                 b.append(((info.mode & 0002) != 0) ? 'w' : '-');
   6167                 b.append(((info.mode & 0001) != 0) ? 'x' : '-');
   6168                 b.append(String.format(" %9d ", info.size));
   6169 
   6170                 Date stamp = new Date(info.mtime);
   6171                 b.append(new SimpleDateFormat("MMM dd HH:mm:ss ").format(stamp));
   6172 
   6173                 b.append(info.packageName);
   6174                 b.append(" :: ");
   6175                 b.append(info.domain);
   6176                 b.append(" :: ");
   6177                 b.append(info.path);
   6178 
   6179                 Slog.i(TAG, b.toString());
   6180             }
   6181         }
   6182 
   6183         // Consume a tar file header block [sequence] and accumulate the relevant metadata
   6184         FileMetadata readTarHeaders(InputStream instream) throws IOException {
   6185             byte[] block = new byte[512];
   6186             FileMetadata info = null;
   6187 
   6188             boolean gotHeader = readTarHeader(instream, block);
   6189             if (gotHeader) {
   6190                 try {
   6191                     // okay, presume we're okay, and extract the various metadata
   6192                     info = new FileMetadata();
   6193                     info.size = extractRadix(block, 124, 12, 8);
   6194                     info.mtime = extractRadix(block, 136, 12, 8);
   6195                     info.mode = extractRadix(block, 100, 8, 8);
   6196 
   6197                     info.path = extractString(block, 345, 155); // prefix
   6198                     String path = extractString(block, 0, 100);
   6199                     if (path.length() > 0) {
   6200                         if (info.path.length() > 0) info.path += '/';
   6201                         info.path += path;
   6202                     }
   6203 
   6204                     // tar link indicator field: 1 byte at offset 156 in the header.
   6205                     int typeChar = block[156];
   6206                     if (typeChar == 'x') {
   6207                         // pax extended header, so we need to read that
   6208                         gotHeader = readPaxExtendedHeader(instream, info);
   6209                         if (gotHeader) {
   6210                             // and after a pax extended header comes another real header -- read
   6211                             // that to find the real file type
   6212                             gotHeader = readTarHeader(instream, block);
   6213                         }
   6214                         if (!gotHeader) throw new IOException("Bad or missing pax header");
   6215 
   6216                         typeChar = block[156];
   6217                     }
   6218 
   6219                     switch (typeChar) {
   6220                         case '0': info.type = BackupAgent.TYPE_FILE; break;
   6221                         case '5': {
   6222                             info.type = BackupAgent.TYPE_DIRECTORY;
   6223                             if (info.size != 0) {
   6224                                 Slog.w(TAG, "Directory entry with nonzero size in header");
   6225                                 info.size = 0;
   6226                             }
   6227                             break;
   6228                         }
   6229                         case 0: {
   6230                             // presume EOF
   6231                             if (MORE_DEBUG) Slog.w(TAG, "Saw type=0 in tar header block, info=" + info);
   6232                             return null;
   6233                         }
   6234                         default: {
   6235                             Slog.e(TAG, "Unknown tar entity type: " + typeChar);
   6236                             throw new IOException("Unknown entity type " + typeChar);
   6237                         }
   6238                     }
   6239 
   6240                     // Parse out the path
   6241                     //
   6242                     // first: apps/shared/unrecognized
   6243                     if (FullBackup.SHARED_PREFIX.regionMatches(0,
   6244                             info.path, 0, FullBackup.SHARED_PREFIX.length())) {
   6245                         // File in shared storage.  !!! TODO: implement this.
   6246                         info.path = info.path.substring(FullBackup.SHARED_PREFIX.length());
   6247                         info.packageName = SHARED_BACKUP_AGENT_PACKAGE;
   6248                         info.domain = FullBackup.SHARED_STORAGE_TOKEN;
   6249                         if (DEBUG) Slog.i(TAG, "File in shared storage: " + info.path);
   6250                     } else if (FullBackup.APPS_PREFIX.regionMatches(0,
   6251                             info.path, 0, FullBackup.APPS_PREFIX.length())) {
   6252                         // App content!  Parse out the package name and domain
   6253 
   6254                         // strip the apps/ prefix
   6255                         info.path = info.path.substring(FullBackup.APPS_PREFIX.length());
   6256 
   6257                         // extract the package name
   6258                         int slash = info.path.indexOf('/');
   6259                         if (slash < 0) throw new IOException("Illegal semantic path in " + info.path);
   6260                         info.packageName = info.path.substring(0, slash);
   6261                         info.path = info.path.substring(slash+1);
   6262 
   6263                         // if it's a manifest or metadata payload we're done, otherwise parse
   6264                         // out the domain into which the file will be restored
   6265                         if (!info.path.equals(BACKUP_MANIFEST_FILENAME)
   6266                                 && !info.path.equals(BACKUP_METADATA_FILENAME)) {
   6267                             slash = info.path.indexOf('/');
   6268                             if (slash < 0) {
   6269                                 throw new IOException("Illegal semantic path in non-manifest "
   6270                                         + info.path);
   6271                             }
   6272                             info.domain = info.path.substring(0, slash);
   6273                             info.path = info.path.substring(slash + 1);
   6274                         }
   6275                     }
   6276                 } catch (IOException e) {
   6277                     if (DEBUG) {
   6278                         Slog.e(TAG, "Parse error in header: " + e.getMessage());
   6279                         if (MORE_DEBUG) {
   6280                             HEXLOG(block);
   6281                         }
   6282                     }
   6283                     throw e;
   6284                 }
   6285             }
   6286             return info;
   6287         }
   6288 
   6289         private boolean isRestorableFile(FileMetadata info) {
   6290             if (FullBackup.CACHE_TREE_TOKEN.equals(info.domain)) {
   6291                 if (MORE_DEBUG) {
   6292                     Slog.i(TAG, "Dropping cache file path " + info.path);
   6293                 }
   6294                 return false;
   6295             }
   6296 
   6297             if (FullBackup.ROOT_TREE_TOKEN.equals(info.domain)) {
   6298                 // It's possible this is "no-backup" dir contents in an archive stream
   6299                 // produced on a device running a version of the OS that predates that
   6300                 // API.  Respect the no-backup intention and don't let the data get to
   6301                 // the app.
   6302                 if (info.path.startsWith("no_backup/")) {
   6303                     if (MORE_DEBUG) {
   6304                         Slog.i(TAG, "Dropping no_backup file path " + info.path);
   6305                     }
   6306                     return false;
   6307                 }
   6308             }
   6309 
   6310             // The path needs to be canonical
   6311             if (info.path.contains("..") || info.path.contains("//")) {
   6312                 if (MORE_DEBUG) {
   6313                     Slog.w(TAG, "Dropping invalid path " + info.path);
   6314                 }
   6315                 return false;
   6316             }
   6317 
   6318             // Otherwise we think this file is good to go
   6319             return true;
   6320         }
   6321 
   6322         private void HEXLOG(byte[] block) {
   6323             int offset = 0;
   6324             int todo = block.length;
   6325             StringBuilder buf = new StringBuilder(64);
   6326             while (todo > 0) {
   6327                 buf.append(String.format("%04x   ", offset));
   6328                 int numThisLine = (todo > 16) ? 16 : todo;
   6329                 for (int i = 0; i < numThisLine; i++) {
   6330                     buf.append(String.format("%02x ", block[offset+i]));
   6331                 }
   6332                 Slog.i("hexdump", buf.toString());
   6333                 buf.setLength(0);
   6334                 todo -= numThisLine;
   6335                 offset += numThisLine;
   6336             }
   6337         }
   6338 
   6339         // Read exactly the given number of bytes into a buffer at the stated offset.
   6340         // Returns false if EOF is encountered before the requested number of bytes
   6341         // could be read.
   6342         int readExactly(InputStream in, byte[] buffer, int offset, int size)
   6343                 throws IOException {
   6344             if (size <= 0) throw new IllegalArgumentException("size must be > 0");
   6345 if (MORE_DEBUG) Slog.i(TAG, "  ... readExactly(" + size + ") called");
   6346             int soFar = 0;
   6347             while (soFar < size) {
   6348                 int nRead = in.read(buffer, offset + soFar, size - soFar);
   6349                 if (nRead <= 0) {
   6350                     if (MORE_DEBUG) Slog.w(TAG, "- wanted exactly " + size + " but got only " + soFar);
   6351                     break;
   6352                 }
   6353                 soFar += nRead;
   6354 if (MORE_DEBUG) Slog.v(TAG, "   + got " + nRead + "; now wanting " + (size - soFar));
   6355             }
   6356             return soFar;
   6357         }
   6358 
   6359         boolean readTarHeader(InputStream instream, byte[] block) throws IOException {
   6360             final int got = readExactly(instream, block, 0, 512);
   6361             if (got == 0) return false;     // Clean EOF
   6362             if (got < 512) throw new IOException("Unable to read full block header");
   6363             mBytes += 512;
   6364             return true;
   6365         }
   6366 
   6367         // overwrites 'info' fields based on the pax extended header
   6368         boolean readPaxExtendedHeader(InputStream instream, FileMetadata info)
   6369                 throws IOException {
   6370             // We should never see a pax extended header larger than this
   6371             if (info.size > 32*1024) {
   6372                 Slog.w(TAG, "Suspiciously large pax header size " + info.size
   6373                         + " - aborting");
   6374                 throw new IOException("Sanity failure: pax header size " + info.size);
   6375             }
   6376 
   6377             // read whole blocks, not just the content size
   6378             int numBlocks = (int)((info.size + 511) >> 9);
   6379             byte[] data = new byte[numBlocks * 512];
   6380             if (readExactly(instream, data, 0, data.length) < data.length) {
   6381                 throw new IOException("Unable to read full pax header");
   6382             }
   6383             mBytes += data.length;
   6384 
   6385             final int contentSize = (int) info.size;
   6386             int offset = 0;
   6387             do {
   6388                 // extract the line at 'offset'
   6389                 int eol = offset+1;
   6390                 while (eol < contentSize && data[eol] != ' ') eol++;
   6391                 if (eol >= contentSize) {
   6392                     // error: we just hit EOD looking for the end of the size field
   6393                     throw new IOException("Invalid pax data");
   6394                 }
   6395                 // eol points to the space between the count and the key
   6396                 int linelen = (int) extractRadix(data, offset, eol - offset, 10);
   6397                 int key = eol + 1;  // start of key=value
   6398                 eol = offset + linelen - 1; // trailing LF
   6399                 int value;
   6400                 for (value = key+1; data[value] != '=' && value <= eol; value++);
   6401                 if (value > eol) {
   6402                     throw new IOException("Invalid pax declaration");
   6403                 }
   6404 
   6405                 // pax requires that key/value strings be in UTF-8
   6406                 String keyStr = new String(data, key, value-key, "UTF-8");
   6407                 // -1 to strip the trailing LF
   6408                 String valStr = new String(data, value+1, eol-value-1, "UTF-8");
   6409 
   6410                 if ("path".equals(keyStr)) {
   6411                     info.path = valStr;
   6412                 } else if ("size".equals(keyStr)) {
   6413                     info.size = Long.parseLong(valStr);
   6414                 } else {
   6415                     if (DEBUG) Slog.i(TAG, "Unhandled pax key: " + key);
   6416                 }
   6417 
   6418                 offset += linelen;
   6419             } while (offset < contentSize);
   6420 
   6421             return true;
   6422         }
   6423 
   6424         long extractRadix(byte[] data, int offset, int maxChars, int radix)
   6425                 throws IOException {
   6426             long value = 0;
   6427             final int end = offset + maxChars;
   6428             for (int i = offset; i < end; i++) {
   6429                 final byte b = data[i];
   6430                 // Numeric fields in tar can terminate with either NUL or SPC
   6431                 if (b == 0 || b == ' ') break;
   6432                 if (b < '0' || b > ('0' + radix - 1)) {
   6433                     throw new IOException("Invalid number in header: '" + (char)b
   6434                             + "' for radix " + radix);
   6435                 }
   6436                 value = radix * value + (b - '0');
   6437             }
   6438             return value;
   6439         }
   6440 
   6441         String extractString(byte[] data, int offset, int maxChars) throws IOException {
   6442             final int end = offset + maxChars;
   6443             int eos = offset;
   6444             // tar string fields terminate early with a NUL
   6445             while (eos < end && data[eos] != 0) eos++;
   6446             return new String(data, offset, eos-offset, "US-ASCII");
   6447         }
   6448 
   6449         void sendStartRestore() {
   6450             if (mObserver != null) {
   6451                 try {
   6452                     mObserver.onStartRestore();
   6453                 } catch (RemoteException e) {
   6454                     Slog.w(TAG, "full restore observer went away: startRestore");
   6455                     mObserver = null;
   6456                 }
   6457             }
   6458         }
   6459 
   6460         void sendOnRestorePackage(String name) {
   6461             if (mObserver != null) {
   6462                 try {
   6463                     // TODO: use a more user-friendly name string
   6464                     mObserver.onRestorePackage(name);
   6465                 } catch (RemoteException e) {
   6466                     Slog.w(TAG, "full restore observer went away: restorePackage");
   6467                     mObserver = null;
   6468                 }
   6469             }
   6470         }
   6471 
   6472         void sendEndRestore() {
   6473             if (mObserver != null) {
   6474                 try {
   6475                     mObserver.onEndRestore();
   6476                 } catch (RemoteException e) {
   6477                     Slog.w(TAG, "full restore observer went away: endRestore");
   6478                     mObserver = null;
   6479                 }
   6480             }
   6481         }
   6482     }
   6483 
   6484     // ***** end new engine class ***
   6485 
   6486     // Used for synchronizing doRestoreFinished during adb restore
   6487     class AdbRestoreFinishedLatch implements BackupRestoreTask {
   6488         static final String TAG = "AdbRestoreFinishedLatch";
   6489         final CountDownLatch mLatch;
   6490 
   6491         AdbRestoreFinishedLatch() {
   6492             mLatch = new CountDownLatch(1);
   6493         }
   6494 
   6495         void await() {
   6496             boolean latched = false;
   6497             try {
   6498                 latched = mLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS);
   6499             } catch (InterruptedException e) {
   6500                 Slog.w(TAG, "Interrupted!");
   6501             }
   6502         }
   6503 
   6504         @Override
   6505         public void execute() {
   6506             // Unused
   6507         }
   6508 
   6509         @Override
   6510         public void operationComplete(long result) {
   6511             if (MORE_DEBUG) {
   6512                 Slog.w(TAG, "adb onRestoreFinished() complete");
   6513             }
   6514             mLatch.countDown();
   6515         }
   6516 
   6517         @Override
   6518         public void handleTimeout() {
   6519             if (DEBUG) {
   6520                 Slog.w(TAG, "adb onRestoreFinished() timed out");
   6521             }
   6522             mLatch.countDown();
   6523         }
   6524     }
   6525 
   6526     class PerformAdbRestoreTask implements Runnable {
   6527         ParcelFileDescriptor mInputFile;
   6528         String mCurrentPassword;
   6529         String mDecryptPassword;
   6530         IFullBackupRestoreObserver mObserver;
   6531         AtomicBoolean mLatchObject;
   6532         IBackupAgent mAgent;
   6533         String mAgentPackage;
   6534         ApplicationInfo mTargetApp;
   6535         FullBackupObbConnection mObbConnection = null;
   6536         ParcelFileDescriptor[] mPipes = null;
   6537         byte[] mWidgetData = null;
   6538 
   6539         long mBytes;
   6540 
   6541         // Runner that can be placed on a separate thread to do in-process invocation
   6542         // of the "restore finished" API asynchronously.  Used by adb restore.
   6543         class RestoreFinishedRunnable implements Runnable {
   6544             final IBackupAgent mAgent;
   6545             final int mToken;
   6546 
   6547             RestoreFinishedRunnable(IBackupAgent agent, int token) {
   6548                 mAgent = agent;
   6549                 mToken = token;
   6550             }
   6551 
   6552             @Override
   6553             public void run() {
   6554                 try {
   6555                     mAgent.doRestoreFinished(mToken, mBackupManagerBinder);
   6556                 } catch (RemoteException e) {
   6557                     // never happens; this is used only for local binder calls
   6558                 }
   6559             }
   6560         }
   6561 
   6562         // possible handling states for a given package in the restore dataset
   6563         final HashMap<String, RestorePolicy> mPackagePolicies
   6564                 = new HashMap<String, RestorePolicy>();
   6565 
   6566         // installer package names for each encountered app, derived from the manifests
   6567         final HashMap<String, String> mPackageInstallers = new HashMap<String, String>();
   6568 
   6569         // Signatures for a given package found in its manifest file
   6570         final HashMap<String, Signature[]> mManifestSignatures
   6571                 = new HashMap<String, Signature[]>();
   6572 
   6573         // Packages we've already wiped data on when restoring their first file
   6574         final HashSet<String> mClearedPackages = new HashSet<String>();
   6575 
   6576         PerformAdbRestoreTask(ParcelFileDescriptor fd, String curPassword, String decryptPassword,
   6577                 IFullBackupRestoreObserver observer, AtomicBoolean latch) {
   6578             mInputFile = fd;
   6579             mCurrentPassword = curPassword;
   6580             mDecryptPassword = decryptPassword;
   6581             mObserver = observer;
   6582             mLatchObject = latch;
   6583             mAgent = null;
   6584             mAgentPackage = null;
   6585             mTargetApp = null;
   6586             mObbConnection = new FullBackupObbConnection();
   6587 
   6588             // Which packages we've already wiped data on.  We prepopulate this
   6589             // with a whitelist of packages known to be unclearable.
   6590             mClearedPackages.add("android");
   6591             mClearedPackages.add(SETTINGS_PACKAGE);
   6592         }
   6593 
   6594         class RestoreFileRunnable implements Runnable {
   6595             IBackupAgent mAgent;
   6596             FileMetadata mInfo;
   6597             ParcelFileDescriptor mSocket;
   6598             int mToken;
   6599 
   6600             RestoreFileRunnable(IBackupAgent agent, FileMetadata info,
   6601                     ParcelFileDescriptor socket, int token) throws IOException {
   6602                 mAgent = agent;
   6603                 mInfo = info;
   6604                 mToken = token;
   6605 
   6606                 // This class is used strictly for process-local binder invocations.  The
   6607                 // semantics of ParcelFileDescriptor differ in this case; in particular, we
   6608                 // do not automatically get a 'dup'ed descriptor that we can can continue
   6609                 // to use asynchronously from the caller.  So, we make sure to dup it ourselves
   6610                 // before proceeding to do the restore.
   6611                 mSocket = ParcelFileDescriptor.dup(socket.getFileDescriptor());
   6612             }
   6613 
   6614             @Override
   6615             public void run() {
   6616                 try {
   6617                     mAgent.doRestoreFile(mSocket, mInfo.size, mInfo.type,
   6618                             mInfo.domain, mInfo.path, mInfo.mode, mInfo.mtime,
   6619                             mToken, mBackupManagerBinder);
   6620                 } catch (RemoteException e) {
   6621                     // never happens; this is used strictly for local binder calls
   6622                 }
   6623             }
   6624         }
   6625 
   6626         @Override
   6627         public void run() {
   6628             Slog.i(TAG, "--- Performing full-dataset restore ---");
   6629             mObbConnection.establish();
   6630             sendStartRestore();
   6631 
   6632             // Are we able to restore shared-storage data?
   6633             if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
   6634                 mPackagePolicies.put(SHARED_BACKUP_AGENT_PACKAGE, RestorePolicy.ACCEPT);
   6635             }
   6636 
   6637             FileInputStream rawInStream = null;
   6638             DataInputStream rawDataIn = null;
   6639             try {
   6640                 if (!backupPasswordMatches(mCurrentPassword)) {
   6641                     if (DEBUG) Slog.w(TAG, "Backup password mismatch; aborting");
   6642                     return;
   6643                 }
   6644 
   6645                 mBytes = 0;
   6646                 byte[] buffer = new byte[32 * 1024];
   6647                 rawInStream = new FileInputStream(mInputFile.getFileDescriptor());
   6648                 rawDataIn = new DataInputStream(rawInStream);
   6649 
   6650                 // First, parse out the unencrypted/uncompressed header
   6651                 boolean compressed = false;
   6652                 InputStream preCompressStream = rawInStream;
   6653                 final InputStream in;
   6654 
   6655                 boolean okay = false;
   6656                 final int headerLen = BACKUP_FILE_HEADER_MAGIC.length();
   6657                 byte[] streamHeader = new byte[headerLen];
   6658                 rawDataIn.readFully(streamHeader);
   6659                 byte[] magicBytes = BACKUP_FILE_HEADER_MAGIC.getBytes("UTF-8");
   6660                 if (Arrays.equals(magicBytes, streamHeader)) {
   6661                     // okay, header looks good.  now parse out the rest of the fields.
   6662                     String s = readHeaderLine(rawInStream);
   6663                     final int archiveVersion = Integer.parseInt(s);
   6664                     if (archiveVersion <= BACKUP_FILE_VERSION) {
   6665                         // okay, it's a version we recognize.  if it's version 1, we may need
   6666                         // to try two different PBKDF2 regimes to compare checksums.
   6667                         final boolean pbkdf2Fallback = (archiveVersion == 1);
   6668 
   6669                         s = readHeaderLine(rawInStream);
   6670                         compressed = (Integer.parseInt(s) != 0);
   6671                         s = readHeaderLine(rawInStream);
   6672                         if (s.equals("none")) {
   6673                             // no more header to parse; we're good to go
   6674                             okay = true;
   6675                         } else if (mDecryptPassword != null && mDecryptPassword.length() > 0) {
   6676                             preCompressStream = decodeAesHeaderAndInitialize(s, pbkdf2Fallback,
   6677                                     rawInStream);
   6678                             if (preCompressStream != null) {
   6679                                 okay = true;
   6680                             }
   6681                         } else Slog.w(TAG, "Archive is encrypted but no password given");
   6682                     } else Slog.w(TAG, "Wrong header version: " + s);
   6683                 } else Slog.w(TAG, "Didn't read the right header magic");
   6684 
   6685                 if (!okay) {
   6686                     Slog.w(TAG, "Invalid restore data; aborting.");
   6687                     return;
   6688                 }
   6689 
   6690                 // okay, use the right stream layer based on compression
   6691                 in = (compressed) ? new InflaterInputStream(preCompressStream) : preCompressStream;
   6692 
   6693                 boolean didRestore;
   6694                 do {
   6695                     didRestore = restoreOneFile(in, buffer);
   6696                 } while (didRestore);
   6697 
   6698                 if (MORE_DEBUG) Slog.v(TAG, "Done consuming input tarfile, total bytes=" + mBytes);
   6699             } catch (IOException e) {
   6700                 Slog.e(TAG, "Unable to read restore input");
   6701             } finally {
   6702                 tearDownPipes();
   6703                 tearDownAgent(mTargetApp, true);
   6704 
   6705                 try {
   6706                     if (rawDataIn != null) rawDataIn.close();
   6707                     if (rawInStream != null) rawInStream.close();
   6708                     mInputFile.close();
   6709                 } catch (IOException e) {
   6710                     Slog.w(TAG, "Close of restore data pipe threw", e);
   6711                     /* nothing we can do about this */
   6712                 }
   6713                 synchronized (mCurrentOpLock) {
   6714                     mCurrentOperations.clear();
   6715                 }
   6716                 synchronized (mLatchObject) {
   6717                     mLatchObject.set(true);
   6718                     mLatchObject.notifyAll();
   6719                 }
   6720                 mObbConnection.tearDown();
   6721                 sendEndRestore();
   6722                 Slog.d(TAG, "Full restore pass complete.");
   6723                 mWakelock.release();
   6724             }
   6725         }
   6726 
   6727         String readHeaderLine(InputStream in) throws IOException {
   6728             int c;
   6729             StringBuilder buffer = new StringBuilder(80);
   6730             while ((c = in.read()) >= 0) {
   6731                 if (c == '\n') break;   // consume and discard the newlines
   6732                 buffer.append((char)c);
   6733             }
   6734             return buffer.toString();
   6735         }
   6736 
   6737         InputStream attemptMasterKeyDecryption(String algorithm, byte[] userSalt, byte[] ckSalt,
   6738                 int rounds, String userIvHex, String masterKeyBlobHex, InputStream rawInStream,
   6739                 boolean doLog) {
   6740             InputStream result = null;
   6741 
   6742             try {
   6743                 Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
   6744                 SecretKey userKey = buildPasswordKey(algorithm, mDecryptPassword, userSalt,
   6745                         rounds);
   6746                 byte[] IV = hexToByteArray(userIvHex);
   6747                 IvParameterSpec ivSpec = new IvParameterSpec(IV);
   6748                 c.init(Cipher.DECRYPT_MODE,
   6749                         new SecretKeySpec(userKey.getEncoded(), "AES"),
   6750                         ivSpec);
   6751                 byte[] mkCipher = hexToByteArray(masterKeyBlobHex);
   6752                 byte[] mkBlob = c.doFinal(mkCipher);
   6753 
   6754                 // first, the master key IV
   6755                 int offset = 0;
   6756                 int len = mkBlob[offset++];
   6757                 IV = Arrays.copyOfRange(mkBlob, offset, offset + len);
   6758                 offset += len;
   6759                 // then the master key itself
   6760                 len = mkBlob[offset++];
   6761                 byte[] mk = Arrays.copyOfRange(mkBlob,
   6762                         offset, offset + len);
   6763                 offset += len;
   6764                 // and finally the master key checksum hash
   6765                 len = mkBlob[offset++];
   6766                 byte[] mkChecksum = Arrays.copyOfRange(mkBlob,
   6767                         offset, offset + len);
   6768 
   6769                 // now validate the decrypted master key against the checksum
   6770                 byte[] calculatedCk = makeKeyChecksum(algorithm, mk, ckSalt, rounds);
   6771                 if (Arrays.equals(calculatedCk, mkChecksum)) {
   6772                     ivSpec = new IvParameterSpec(IV);
   6773                     c.init(Cipher.DECRYPT_MODE,
   6774                             new SecretKeySpec(mk, "AES"),
   6775                             ivSpec);
   6776                     // Only if all of the above worked properly will 'result' be assigned
   6777                     result = new CipherInputStream(rawInStream, c);
   6778                 } else if (doLog) Slog.w(TAG, "Incorrect password");
   6779             } catch (InvalidAlgorithmParameterException e) {
   6780                 if (doLog) Slog.e(TAG, "Needed parameter spec unavailable!", e);
   6781             } catch (BadPaddingException e) {
   6782                 // This case frequently occurs when the wrong password is used to decrypt
   6783                 // the master key.  Use the identical "incorrect password" log text as is
   6784                 // used in the checksum failure log in order to avoid providing additional
   6785                 // information to an attacker.
   6786                 if (doLog) Slog.w(TAG, "Incorrect password");
   6787             } catch (IllegalBlockSizeException e) {
   6788                 if (doLog) Slog.w(TAG, "Invalid block size in master key");
   6789             } catch (NoSuchAlgorithmException e) {
   6790                 if (doLog) Slog.e(TAG, "Needed decryption algorithm unavailable!");
   6791             } catch (NoSuchPaddingException e) {
   6792                 if (doLog) Slog.e(TAG, "Needed padding mechanism unavailable!");
   6793             } catch (InvalidKeyException e) {
   6794                 if (doLog) Slog.w(TAG, "Illegal password; aborting");
   6795             }
   6796 
   6797             return result;
   6798         }
   6799 
   6800         InputStream decodeAesHeaderAndInitialize(String encryptionName, boolean pbkdf2Fallback,
   6801                 InputStream rawInStream) {
   6802             InputStream result = null;
   6803             try {
   6804                 if (encryptionName.equals(ENCRYPTION_ALGORITHM_NAME)) {
   6805 
   6806                     String userSaltHex = readHeaderLine(rawInStream); // 5
   6807                     byte[] userSalt = hexToByteArray(userSaltHex);
   6808 
   6809                     String ckSaltHex = readHeaderLine(rawInStream); // 6
   6810                     byte[] ckSalt = hexToByteArray(ckSaltHex);
   6811 
   6812                     int rounds = Integer.parseInt(readHeaderLine(rawInStream)); // 7
   6813                     String userIvHex = readHeaderLine(rawInStream); // 8
   6814 
   6815                     String masterKeyBlobHex = readHeaderLine(rawInStream); // 9
   6816 
   6817                     // decrypt the master key blob
   6818                     result = attemptMasterKeyDecryption(PBKDF_CURRENT, userSalt, ckSalt,
   6819                             rounds, userIvHex, masterKeyBlobHex, rawInStream, false);
   6820                     if (result == null && pbkdf2Fallback) {
   6821                         result = attemptMasterKeyDecryption(PBKDF_FALLBACK, userSalt, ckSalt,
   6822                                 rounds, userIvHex, masterKeyBlobHex, rawInStream, true);
   6823                     }
   6824                 } else Slog.w(TAG, "Unsupported encryption method: " + encryptionName);
   6825             } catch (NumberFormatException e) {
   6826                 Slog.w(TAG, "Can't parse restore data header");
   6827             } catch (IOException e) {
   6828                 Slog.w(TAG, "Can't read input header");
   6829             }
   6830 
   6831             return result;
   6832         }
   6833 
   6834         boolean restoreOneFile(InputStream instream, byte[] buffer) {
   6835             FileMetadata info;
   6836             try {
   6837                 info = readTarHeaders(instream);
   6838                 if (info != null) {
   6839                     if (MORE_DEBUG) {
   6840                         dumpFileMetadata(info);
   6841                     }
   6842 
   6843                     final String pkg = info.packageName;
   6844                     if (!pkg.equals(mAgentPackage)) {
   6845                         // okay, change in package; set up our various
   6846                         // bookkeeping if we haven't seen it yet
   6847                         if (!mPackagePolicies.containsKey(pkg)) {
   6848                             mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
   6849                         }
   6850 
   6851                         // Clean up the previous agent relationship if necessary,
   6852                         // and let the observer know we're considering a new app.
   6853                         if (mAgent != null) {
   6854                             if (DEBUG) Slog.d(TAG, "Saw new package; finalizing old one");
   6855                             // Now we're really done
   6856                             tearDownPipes();
   6857                             tearDownAgent(mTargetApp, true);
   6858                             mTargetApp = null;
   6859                             mAgentPackage = null;
   6860                         }
   6861                     }
   6862 
   6863                     if (info.path.equals(BACKUP_MANIFEST_FILENAME)) {
   6864                         mPackagePolicies.put(pkg, readAppManifest(info, instream));
   6865                         mPackageInstallers.put(pkg, info.installerPackageName);
   6866                         // We've read only the manifest content itself at this point,
   6867                         // so consume the footer before looping around to the next
   6868                         // input file
   6869                         skipTarPadding(info.size, instream);
   6870                         sendOnRestorePackage(pkg);
   6871                     } else if (info.path.equals(BACKUP_METADATA_FILENAME)) {
   6872                         // Metadata blobs!
   6873                         readMetadata(info, instream);
   6874                         skipTarPadding(info.size, instream);
   6875                     } else {
   6876                         // Non-manifest, so it's actual file data.  Is this a package
   6877                         // we're ignoring?
   6878                         boolean okay = true;
   6879                         RestorePolicy policy = mPackagePolicies.get(pkg);
   6880                         switch (policy) {
   6881                             case IGNORE:
   6882                                 okay = false;
   6883                                 break;
   6884 
   6885                             case ACCEPT_IF_APK:
   6886                                 // If we're in accept-if-apk state, then the first file we
   6887                                 // see MUST be the apk.
   6888                                 if (info.domain.equals(FullBackup.APK_TREE_TOKEN)) {
   6889                                     if (DEBUG) Slog.d(TAG, "APK file; installing");
   6890                                     // Try to install the app.
   6891                                     String installerName = mPackageInstallers.get(pkg);
   6892                                     okay = installApk(info, installerName, instream);
   6893                                     // good to go; promote to ACCEPT
   6894                                     mPackagePolicies.put(pkg, (okay)
   6895                                             ? RestorePolicy.ACCEPT
   6896                                             : RestorePolicy.IGNORE);
   6897                                     // At this point we've consumed this file entry
   6898                                     // ourselves, so just strip the tar footer and
   6899                                     // go on to the next file in the input stream
   6900                                     skipTarPadding(info.size, instream);
   6901                                     return true;
   6902                                 } else {
   6903                                     // File data before (or without) the apk.  We can't
   6904                                     // handle it coherently in this case so ignore it.
   6905                                     mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
   6906                                     okay = false;
   6907                                 }
   6908                                 break;
   6909 
   6910                             case ACCEPT:
   6911                                 if (info.domain.equals(FullBackup.APK_TREE_TOKEN)) {
   6912                                     if (DEBUG) Slog.d(TAG, "apk present but ACCEPT");
   6913                                     // we can take the data without the apk, so we
   6914                                     // *want* to do so.  skip the apk by declaring this
   6915                                     // one file not-okay without changing the restore
   6916                                     // policy for the package.
   6917                                     okay = false;
   6918                                 }
   6919                                 break;
   6920 
   6921                             default:
   6922                                 // Something has gone dreadfully wrong when determining
   6923                                 // the restore policy from the manifest.  Ignore the
   6924                                 // rest of this package's data.
   6925                                 Slog.e(TAG, "Invalid policy from manifest");
   6926                                 okay = false;
   6927                                 mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
   6928                                 break;
   6929                         }
   6930 
   6931                         // The path needs to be canonical
   6932                         if (info.path.contains("..") || info.path.contains("//")) {
   6933                             if (MORE_DEBUG) {
   6934                                 Slog.w(TAG, "Dropping invalid path " + info.path);
   6935                             }
   6936                             okay = false;
   6937                         }
   6938 
   6939                         // If the policy is satisfied, go ahead and set up to pipe the
   6940                         // data to the agent.
   6941                         if (DEBUG && okay && mAgent != null) {
   6942                             Slog.i(TAG, "Reusing existing agent instance");
   6943                         }
   6944                         if (okay && mAgent == null) {
   6945                             if (DEBUG) Slog.d(TAG, "Need to launch agent for " + pkg);
   6946 
   6947                             try {
   6948                                 mTargetApp = mPackageManager.getApplicationInfo(pkg, 0);
   6949 
   6950                                 // If we haven't sent any data to this app yet, we probably
   6951                                 // need to clear it first.  Check that.
   6952                                 if (!mClearedPackages.contains(pkg)) {
   6953                                     // apps with their own backup agents are
   6954                                     // responsible for coherently managing a full
   6955                                     // restore.
   6956                                     if (mTargetApp.backupAgentName == null) {
   6957                                         if (DEBUG) Slog.d(TAG, "Clearing app data preparatory to full restore");
   6958                                         clearApplicationDataSynchronous(pkg);
   6959                                     } else {
   6960                                         if (DEBUG) Slog.d(TAG, "backup agent ("
   6961                                                 + mTargetApp.backupAgentName + ") => no clear");
   6962                                     }
   6963                                     mClearedPackages.add(pkg);
   6964                                 } else {
   6965                                     if (DEBUG) Slog.d(TAG, "We've initialized this app already; no clear required");
   6966                                 }
   6967 
   6968                                 // All set; now set up the IPC and launch the agent
   6969                                 setUpPipes();
   6970                                 mAgent = bindToAgentSynchronous(mTargetApp,
   6971                                         IApplicationThread.BACKUP_MODE_RESTORE_FULL);
   6972                                 mAgentPackage = pkg;
   6973                             } catch (IOException e) {
   6974                                 // fall through to error handling
   6975                             } catch (NameNotFoundException e) {
   6976                                 // fall through to error handling
   6977                             }
   6978 
   6979                             if (mAgent == null) {
   6980                                 if (DEBUG) Slog.d(TAG, "Unable to create agent for " + pkg);
   6981                                 okay = false;
   6982                                 tearDownPipes();
   6983                                 mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
   6984                             }
   6985                         }
   6986 
   6987                         // Sanity check: make sure we never give data to the wrong app.  This
   6988                         // should never happen but a little paranoia here won't go amiss.
   6989                         if (okay && !pkg.equals(mAgentPackage)) {
   6990                             Slog.e(TAG, "Restoring data for " + pkg
   6991                                     + " but agent is for " + mAgentPackage);
   6992                             okay = false;
   6993                         }
   6994 
   6995                         // At this point we have an agent ready to handle the full
   6996                         // restore data as well as a pipe for sending data to
   6997                         // that agent.  Tell the agent to start reading from the
   6998                         // pipe.
   6999                         if (okay) {
   7000                             boolean agentSuccess = true;
   7001                             long toCopy = info.size;
   7002                             final int token = generateToken();
   7003                             try {
   7004                                 prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL, null);
   7005                                 if (info.domain.equals(FullBackup.OBB_TREE_TOKEN)) {
   7006                                     if (DEBUG) Slog.d(TAG, "Restoring OBB file for " + pkg
   7007                                             + " : " + info.path);
   7008                                     mObbConnection.restoreObbFile(pkg, mPipes[0],
   7009                                             info.size, info.type, info.path, info.mode,
   7010                                             info.mtime, token, mBackupManagerBinder);
   7011                                 } else {
   7012                                     if (DEBUG) Slog.d(TAG, "Invoking agent to restore file "
   7013                                             + info.path);
   7014                                     // fire up the app's agent listening on the socket.  If
   7015                                     // the agent is running in the system process we can't
   7016                                     // just invoke it asynchronously, so we provide a thread
   7017                                     // for it here.
   7018                                     if (mTargetApp.processName.equals("system")) {
   7019                                         Slog.d(TAG, "system process agent - spinning a thread");
   7020                                         RestoreFileRunnable runner = new RestoreFileRunnable(
   7021                                                 mAgent, info, mPipes[0], token);
   7022                                         new Thread(runner, "restore-sys-runner").start();
   7023                                     } else {
   7024                                         mAgent.doRestoreFile(mPipes[0], info.size, info.type,
   7025                                                 info.domain, info.path, info.mode, info.mtime,
   7026                                                 token, mBackupManagerBinder);
   7027                                     }
   7028                                 }
   7029                             } catch (IOException e) {
   7030                                 // couldn't dup the socket for a process-local restore
   7031                                 Slog.d(TAG, "Couldn't establish restore");
   7032                                 agentSuccess = false;
   7033                                 okay = false;
   7034                             } catch (RemoteException e) {
   7035                                 // whoops, remote entity went away.  We'll eat the content
   7036                                 // ourselves, then, and not copy it over.
   7037                                 Slog.e(TAG, "Agent crashed during full restore");
   7038                                 agentSuccess = false;
   7039                                 okay = false;
   7040                             }
   7041 
   7042                             // Copy over the data if the agent is still good
   7043                             if (okay) {
   7044                                 boolean pipeOkay = true;
   7045                                 FileOutputStream pipe = new FileOutputStream(
   7046                                         mPipes[1].getFileDescriptor());
   7047                                 while (toCopy > 0) {
   7048                                     int toRead = (toCopy > buffer.length)
   7049                                     ? buffer.length : (int)toCopy;
   7050                                     int nRead = instream.read(buffer, 0, toRead);
   7051                                     if (nRead >= 0) mBytes += nRead;
   7052                                     if (nRead <= 0) break;
   7053                                     toCopy -= nRead;
   7054 
   7055                                     // send it to the output pipe as long as things
   7056                                     // are still good
   7057                                     if (pipeOkay) {
   7058                                         try {
   7059                                             pipe.write(buffer, 0, nRead);
   7060                                         } catch (IOException e) {
   7061                                             Slog.e(TAG, "Failed to write to restore pipe", e);
   7062                                             pipeOkay = false;
   7063                                         }
   7064                                     }
   7065                                 }
   7066 
   7067                                 // done sending that file!  Now we just need to consume
   7068                                 // the delta from info.size to the end of block.
   7069                                 skipTarPadding(info.size, instream);
   7070 
   7071                                 // and now that we've sent it all, wait for the remote
   7072                                 // side to acknowledge receipt
   7073                                 agentSuccess = waitUntilOperationComplete(token);
   7074                             }
   7075 
   7076                             // okay, if the remote end failed at any point, deal with
   7077                             // it by ignoring the rest of the restore on it
   7078                             if (!agentSuccess) {
   7079                                 if (DEBUG) {
   7080                                     Slog.d(TAG, "Agent failure restoring " + pkg + "; now ignoring");
   7081                                 }
   7082                                 mBackupHandler.removeMessages(MSG_TIMEOUT);
   7083                                 tearDownPipes();
   7084                                 tearDownAgent(mTargetApp, false);
   7085                                 mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
   7086                             }
   7087                         }
   7088 
   7089                         // Problems setting up the agent communication, or an already-
   7090                         // ignored package: skip to the next tar stream entry by
   7091                         // reading and discarding this file.
   7092                         if (!okay) {
   7093                             if (DEBUG) Slog.d(TAG, "[discarding file content]");
   7094                             long bytesToConsume = (info.size + 511) & ~511;
   7095                             while (bytesToConsume > 0) {
   7096                                 int toRead = (bytesToConsume > buffer.length)
   7097                                 ? buffer.length : (int)bytesToConsume;
   7098                                 long nRead = instream.read(buffer, 0, toRead);
   7099                                 if (nRead >= 0) mBytes += nRead;
   7100                                 if (nRead <= 0) break;
   7101                                 bytesToConsume -= nRead;
   7102                             }
   7103                         }
   7104                     }
   7105                 }
   7106             } catch (IOException e) {
   7107                 if (DEBUG) Slog.w(TAG, "io exception on restore socket read", e);
   7108                 // treat as EOF
   7109                 info = null;
   7110             }
   7111 
   7112             return (info != null);
   7113         }
   7114 
   7115         void setUpPipes() throws IOException {
   7116             mPipes = ParcelFileDescriptor.createPipe();
   7117         }
   7118 
   7119         void tearDownPipes() {
   7120             if (mPipes != null) {
   7121                 try {
   7122                     mPipes[0].close();
   7123                     mPipes[0] = null;
   7124                     mPipes[1].close();
   7125                     mPipes[1] = null;
   7126                 } catch (IOException e) {
   7127                     Slog.w(TAG, "Couldn't close agent pipes", e);
   7128                 }
   7129                 mPipes = null;
   7130             }
   7131         }
   7132 
   7133         void tearDownAgent(ApplicationInfo app, boolean doRestoreFinished) {
   7134             if (mAgent != null) {
   7135                 try {
   7136                     // In the adb restore case, we do restore-finished here
   7137                     if (doRestoreFinished) {
   7138                         final int token = generateToken();
   7139                         final AdbRestoreFinishedLatch latch = new AdbRestoreFinishedLatch();
   7140                         prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL, latch);
   7141                         if (mTargetApp.processName.equals("system")) {
   7142                             if (MORE_DEBUG) {
   7143                                 Slog.d(TAG, "system agent - restoreFinished on thread");
   7144                             }
   7145                             Runnable runner = new RestoreFinishedRunnable(mAgent, token);
   7146                             new Thread(runner, "restore-sys-finished-runner").start();
   7147                         } else {
   7148                             mAgent.doRestoreFinished(token, mBackupManagerBinder);
   7149                         }
   7150 
   7151                         latch.await();
   7152                     }
   7153 
   7154                     // unbind and tidy up even on timeout or failure, just in case
   7155                     mActivityManager.unbindBackupAgent(app);
   7156 
   7157                     // The agent was running with a stub Application object, so shut it down.
   7158                     // !!! We hardcode the confirmation UI's package name here rather than use a
   7159                     //     manifest flag!  TODO something less direct.
   7160                     if (app.uid >= Process.FIRST_APPLICATION_UID
   7161                             && !app.packageName.equals("com.android.backupconfirm")) {
   7162                         if (DEBUG) Slog.d(TAG, "Killing host process");
   7163                         mActivityManager.killApplicationProcess(app.processName, app.uid);
   7164                     } else {
   7165                         if (DEBUG) Slog.d(TAG, "Not killing after full restore");
   7166                     }
   7167                 } catch (RemoteException e) {
   7168                     Slog.d(TAG, "Lost app trying to shut down");
   7169                 }
   7170                 mAgent = null;
   7171             }
   7172         }
   7173 
   7174         class RestoreInstallObserver extends PackageInstallObserver {
   7175             final AtomicBoolean mDone = new AtomicBoolean();
   7176             String mPackageName;
   7177             int mResult;
   7178 
   7179             public void reset() {
   7180                 synchronized (mDone) {
   7181                     mDone.set(false);
   7182                 }
   7183             }
   7184 
   7185             public void waitForCompletion() {
   7186                 synchronized (mDone) {
   7187                     while (mDone.get() == false) {
   7188                         try {
   7189                             mDone.wait();
   7190                         } catch (InterruptedException e) { }
   7191                     }
   7192                 }
   7193             }
   7194 
   7195             int getResult() {
   7196                 return mResult;
   7197             }
   7198 
   7199             @Override
   7200             public void onPackageInstalled(String packageName, int returnCode,
   7201                     String msg, Bundle extras) {
   7202                 synchronized (mDone) {
   7203                     mResult = returnCode;
   7204                     mPackageName = packageName;
   7205                     mDone.set(true);
   7206                     mDone.notifyAll();
   7207                 }
   7208             }
   7209         }
   7210 
   7211         class RestoreDeleteObserver extends IPackageDeleteObserver.Stub {
   7212             final AtomicBoolean mDone = new AtomicBoolean();
   7213             int mResult;
   7214 
   7215             public void reset() {
   7216                 synchronized (mDone) {
   7217                     mDone.set(false);
   7218                 }
   7219             }
   7220 
   7221             public void waitForCompletion() {
   7222                 synchronized (mDone) {
   7223                     while (mDone.get() == false) {
   7224                         try {
   7225                             mDone.wait();
   7226                         } catch (InterruptedException e) { }
   7227                     }
   7228                 }
   7229             }
   7230 
   7231             @Override
   7232             public void packageDeleted(String packageName, int returnCode) throws RemoteException {
   7233                 synchronized (mDone) {
   7234                     mResult = returnCode;
   7235                     mDone.set(true);
   7236                     mDone.notifyAll();
   7237                 }
   7238             }
   7239         }
   7240 
   7241         final RestoreInstallObserver mInstallObserver = new RestoreInstallObserver();
   7242         final RestoreDeleteObserver mDeleteObserver = new RestoreDeleteObserver();
   7243 
   7244         boolean installApk(FileMetadata info, String installerPackage, InputStream instream) {
   7245             boolean okay = true;
   7246 
   7247             if (DEBUG) Slog.d(TAG, "Installing from backup: " + info.packageName);
   7248 
   7249             // The file content is an .apk file.  Copy it out to a staging location and
   7250             // attempt to install it.
   7251             File apkFile = new File(mDataDir, info.packageName);
   7252             try {
   7253                 FileOutputStream apkStream = new FileOutputStream(apkFile);
   7254                 byte[] buffer = new byte[32 * 1024];
   7255                 long size = info.size;
   7256                 while (size > 0) {
   7257                     long toRead = (buffer.length < size) ? buffer.length : size;
   7258                     int didRead = instream.read(buffer, 0, (int)toRead);
   7259                     if (didRead >= 0) mBytes += didRead;
   7260                     apkStream.write(buffer, 0, didRead);
   7261                     size -= didRead;
   7262                 }
   7263                 apkStream.close();
   7264 
   7265                 // make sure the installer can read it
   7266                 apkFile.setReadable(true, false);
   7267 
   7268                 // Now install it
   7269                 Uri packageUri = Uri.fromFile(apkFile);
   7270                 mInstallObserver.reset();
   7271                 mPackageManager.installPackage(packageUri, mInstallObserver,
   7272                         PackageManager.INSTALL_REPLACE_EXISTING | PackageManager.INSTALL_FROM_ADB,
   7273                         installerPackage);
   7274                 mInstallObserver.waitForCompletion();
   7275 
   7276                 if (mInstallObserver.getResult() != PackageManager.INSTALL_SUCCEEDED) {
   7277                     // The only time we continue to accept install of data even if the
   7278                     // apk install failed is if we had already determined that we could
   7279                     // accept the data regardless.
   7280                     if (mPackagePolicies.get(info.packageName) != RestorePolicy.ACCEPT) {
   7281                         okay = false;
   7282                     }
   7283                 } else {
   7284                     // Okay, the install succeeded.  Make sure it was the right app.
   7285                     boolean uninstall = false;
   7286                     if (!mInstallObserver.mPackageName.equals(info.packageName)) {
   7287                         Slog.w(TAG, "Restore stream claimed to include apk for "
   7288                                 + info.packageName + " but apk was really "
   7289                                 + mInstallObserver.mPackageName);
   7290                         // delete the package we just put in place; it might be fraudulent
   7291                         okay = false;
   7292                         uninstall = true;
   7293                     } else {
   7294                         try {
   7295                             PackageInfo pkg = mPackageManager.getPackageInfo(info.packageName,
   7296                                     PackageManager.GET_SIGNATURES);
   7297                             if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) {
   7298                                 Slog.w(TAG, "Restore stream contains apk of package "
   7299                                         + info.packageName + " but it disallows backup/restore");
   7300                                 okay = false;
   7301                             } else {
   7302                                 // So far so good -- do the signatures match the manifest?
   7303                                 Signature[] sigs = mManifestSignatures.get(info.packageName);
   7304                                 if (signaturesMatch(sigs, pkg)) {
   7305                                     // If this is a system-uid app without a declared backup agent,
   7306                                     // don't restore any of the file data.
   7307                                     if ((pkg.applicationInfo.uid < Process.FIRST_APPLICATION_UID)
   7308                                             && (pkg.applicationInfo.backupAgentName == null)) {
   7309                                         Slog.w(TAG, "Installed app " + info.packageName
   7310                                                 + " has restricted uid and no agent");
   7311                                         okay = false;
   7312                                     }
   7313                                 } else {
   7314                                     Slog.w(TAG, "Installed app " + info.packageName
   7315                                             + " signatures do not match restore manifest");
   7316                                     okay = false;
   7317                                     uninstall = true;
   7318                                 }
   7319                             }
   7320                         } catch (NameNotFoundException e) {
   7321                             Slog.w(TAG, "Install of package " + info.packageName
   7322                                     + " succeeded but now not found");
   7323                             okay = false;
   7324                         }
   7325                     }
   7326 
   7327                     // If we're not okay at this point, we need to delete the package
   7328                     // that we just installed.
   7329                     if (uninstall) {
   7330                         mDeleteObserver.reset();
   7331                         mPackageManager.deletePackage(mInstallObserver.mPackageName,
   7332                                 mDeleteObserver, 0);
   7333                         mDeleteObserver.waitForCompletion();
   7334                     }
   7335                 }
   7336             } catch (IOException e) {
   7337                 Slog.e(TAG, "Unable to transcribe restored apk for install");
   7338                 okay = false;
   7339             } finally {
   7340                 apkFile.delete();
   7341             }
   7342 
   7343             return okay;
   7344         }
   7345 
   7346         // Given an actual file content size, consume the post-content padding mandated
   7347         // by the tar format.
   7348         void skipTarPadding(long size, InputStream instream) throws IOException {
   7349             long partial = (size + 512) % 512;
   7350             if (partial > 0) {
   7351                 final int needed = 512 - (int)partial;
   7352                 byte[] buffer = new byte[needed];
   7353                 if (readExactly(instream, buffer, 0, needed) == needed) {
   7354                     mBytes += needed;
   7355                 } else throw new IOException("Unexpected EOF in padding");
   7356             }
   7357         }
   7358 
   7359         // Read a widget metadata file, returning the restored blob
   7360         void readMetadata(FileMetadata info, InputStream instream) throws IOException {
   7361             // Fail on suspiciously large widget dump files
   7362             if (info.size > 64 * 1024) {
   7363                 throw new IOException("Metadata too big; corrupt? size=" + info.size);
   7364             }
   7365 
   7366             byte[] buffer = new byte[(int) info.size];
   7367             if (readExactly(instream, buffer, 0, (int)info.size) == info.size) {
   7368                 mBytes += info.size;
   7369             } else throw new IOException("Unexpected EOF in widget data");
   7370 
   7371             String[] str = new String[1];
   7372             int offset = extractLine(buffer, 0, str);
   7373             int version = Integer.parseInt(str[0]);
   7374             if (version == BACKUP_MANIFEST_VERSION) {
   7375                 offset = extractLine(buffer, offset, str);
   7376                 final String pkg = str[0];
   7377                 if (info.packageName.equals(pkg)) {
   7378                     // Data checks out -- the rest of the buffer is a concatenation of
   7379                     // binary blobs as described in the comment at writeAppWidgetData()
   7380                     ByteArrayInputStream bin = new ByteArrayInputStream(buffer,
   7381                             offset, buffer.length - offset);
   7382                     DataInputStream in = new DataInputStream(bin);
   7383                     while (bin.available() > 0) {
   7384                         int token = in.readInt();
   7385                         int size = in.readInt();
   7386                         if (size > 64 * 1024) {
   7387                             throw new IOException("Datum "
   7388                                     + Integer.toHexString(token)
   7389                                     + " too big; corrupt? size=" + info.size);
   7390                         }
   7391                         switch (token) {
   7392                             case BACKUP_WIDGET_METADATA_TOKEN:
   7393                             {
   7394                                 if (MORE_DEBUG) {
   7395                                     Slog.i(TAG, "Got widget metadata for " + info.packageName);
   7396                                 }
   7397                                 mWidgetData = new byte[size];
   7398                                 in.read(mWidgetData);
   7399                                 break;
   7400                             }
   7401                             default:
   7402                             {
   7403                                 if (DEBUG) {
   7404                                     Slog.i(TAG, "Ignoring metadata blob "
   7405                                             + Integer.toHexString(token)
   7406                                             + " for " + info.packageName);
   7407                                 }
   7408                                 in.skipBytes(size);
   7409                                 break;
   7410                             }
   7411                         }
   7412                     }
   7413                 } else {
   7414                     Slog.w(TAG, "Metadata mismatch: package " + info.packageName
   7415                             + " but widget data for " + pkg);
   7416                 }
   7417             } else {
   7418                 Slog.w(TAG, "Unsupported metadata version " + version);
   7419             }
   7420         }
   7421 
   7422         // Returns a policy constant; takes a buffer arg to reduce memory churn
   7423         RestorePolicy readAppManifest(FileMetadata info, InputStream instream)
   7424                 throws IOException {
   7425             // Fail on suspiciously large manifest files
   7426             if (info.size > 64 * 1024) {
   7427                 throw new IOException("Restore manifest too big; corrupt? size=" + info.size);
   7428             }
   7429 
   7430             byte[] buffer = new byte[(int) info.size];
   7431             if (readExactly(instream, buffer, 0, (int)info.size) == info.size) {
   7432                 mBytes += info.size;
   7433             } else throw new IOException("Unexpected EOF in manifest");
   7434 
   7435             RestorePolicy policy = RestorePolicy.IGNORE;
   7436             String[] str = new String[1];
   7437             int offset = 0;
   7438 
   7439             try {
   7440                 offset = extractLine(buffer, offset, str);
   7441                 int version = Integer.parseInt(str[0]);
   7442                 if (version == BACKUP_MANIFEST_VERSION) {
   7443                     offset = extractLine(buffer, offset, str);
   7444                     String manifestPackage = str[0];
   7445                     // TODO: handle <original-package>
   7446                     if (manifestPackage.equals(info.packageName)) {
   7447                         offset = extractLine(buffer, offset, str);
   7448                         version = Integer.parseInt(str[0]);  // app version
   7449                         offset = extractLine(buffer, offset, str);
   7450                         // This is the platform version, which we don't use, but we parse it
   7451                         // as a safety against corruption in the manifest.
   7452                         Integer.parseInt(str[0]);
   7453                         offset = extractLine(buffer, offset, str);
   7454                         info.installerPackageName = (str[0].length() > 0) ? str[0] : null;
   7455                         offset = extractLine(buffer, offset, str);
   7456                         boolean hasApk = str[0].equals("1");
   7457                         offset = extractLine(buffer, offset, str);
   7458                         int numSigs = Integer.parseInt(str[0]);
   7459                         if (numSigs > 0) {
   7460                             Signature[] sigs = new Signature[numSigs];
   7461                             for (int i = 0; i < numSigs; i++) {
   7462                                 offset = extractLine(buffer, offset, str);
   7463                                 sigs[i] = new Signature(str[0]);
   7464                             }
   7465                             mManifestSignatures.put(info.packageName, sigs);
   7466 
   7467                             // Okay, got the manifest info we need...
   7468                             try {
   7469                                 PackageInfo pkgInfo = mPackageManager.getPackageInfo(
   7470                                         info.packageName, PackageManager.GET_SIGNATURES);
   7471                                 // Fall through to IGNORE if the app explicitly disallows backup
   7472                                 final int flags = pkgInfo.applicationInfo.flags;
   7473                                 if ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0) {
   7474                                     // Restore system-uid-space packages only if they have
   7475                                     // defined a custom backup agent
   7476                                     if ((pkgInfo.applicationInfo.uid >= Process.FIRST_APPLICATION_UID)
   7477                                             || (pkgInfo.applicationInfo.backupAgentName != null)) {
   7478                                         // Verify signatures against any installed version; if they
   7479                                         // don't match, then we fall though and ignore the data.  The
   7480                                         // signatureMatch() method explicitly ignores the signature
   7481                                         // check for packages installed on the system partition, because
   7482                                         // such packages are signed with the platform cert instead of
   7483                                         // the app developer's cert, so they're different on every
   7484                                         // device.
   7485                                         if (signaturesMatch(sigs, pkgInfo)) {
   7486                                             if ((pkgInfo.applicationInfo.flags
   7487                                                     & ApplicationInfo.FLAG_RESTORE_ANY_VERSION) != 0) {
   7488                                                 Slog.i(TAG, "Package has restoreAnyVersion; taking data");
   7489                                                 policy = RestorePolicy.ACCEPT;
   7490                                             } else if (pkgInfo.versionCode >= version) {
   7491                                                 Slog.i(TAG, "Sig + version match; taking data");
   7492                                                 policy = RestorePolicy.ACCEPT;
   7493                                             } else {
   7494                                                 // The data is from a newer version of the app than
   7495                                                 // is presently installed.  That means we can only
   7496                                                 // use it if the matching apk is also supplied.
   7497                                                 Slog.d(TAG, "Data version " + version
   7498                                                         + " is newer than installed version "
   7499                                                         + pkgInfo.versionCode + " - requiring apk");
   7500                                                 policy = RestorePolicy.ACCEPT_IF_APK;
   7501                                             }
   7502                                         } else {
   7503                                             Slog.w(TAG, "Restore manifest signatures do not match "
   7504                                                     + "installed application for " + info.packageName);
   7505                                         }
   7506                                     } else {
   7507                                         Slog.w(TAG, "Package " + info.packageName
   7508                                                 + " is system level with no agent");
   7509                                     }
   7510                                 } else {
   7511                                     if (DEBUG) Slog.i(TAG, "Restore manifest from "
   7512                                             + info.packageName + " but allowBackup=false");
   7513                                 }
   7514                             } catch (NameNotFoundException e) {
   7515                                 // Okay, the target app isn't installed.  We can process
   7516                                 // the restore properly only if the dataset provides the
   7517                                 // apk file and we can successfully install it.
   7518                                 if (DEBUG) Slog.i(TAG, "Package " + info.packageName
   7519                                         + " not installed; requiring apk in dataset");
   7520                                 policy = RestorePolicy.ACCEPT_IF_APK;
   7521                             }
   7522 
   7523                             if (policy == RestorePolicy.ACCEPT_IF_APK && !hasApk) {
   7524                                 Slog.i(TAG, "Cannot restore package " + info.packageName
   7525                                         + " without the matching .apk");
   7526                             }
   7527                         } else {
   7528                             Slog.i(TAG, "Missing signature on backed-up package "
   7529                                     + info.packageName);
   7530                         }
   7531                     } else {
   7532                         Slog.i(TAG, "Expected package " + info.packageName
   7533                                 + " but restore manifest claims " + manifestPackage);
   7534                     }
   7535                 } else {
   7536                     Slog.i(TAG, "Unknown restore manifest version " + version
   7537                             + " for package " + info.packageName);
   7538                 }
   7539             } catch (NumberFormatException e) {
   7540                 Slog.w(TAG, "Corrupt restore manifest for package " + info.packageName);
   7541             } catch (IllegalArgumentException e) {
   7542                 Slog.w(TAG, e.getMessage());
   7543             }
   7544 
   7545             return policy;
   7546         }
   7547 
   7548         // Builds a line from a byte buffer starting at 'offset', and returns
   7549         // the index of the next unconsumed data in the buffer.
   7550         int extractLine(byte[] buffer, int offset, String[] outStr) throws IOException {
   7551             final int end = buffer.length;
   7552             if (offset >= end) throw new IOException("Incomplete data");
   7553 
   7554             int pos;
   7555             for (pos = offset; pos < end; pos++) {
   7556                 byte c = buffer[pos];
   7557                 // at LF we declare end of line, and return the next char as the
   7558                 // starting point for the next time through
   7559                 if (c == '\n') {
   7560                     break;
   7561                 }
   7562             }
   7563             outStr[0] = new String(buffer, offset, pos - offset);
   7564             pos++;  // may be pointing an extra byte past the end but that's okay
   7565             return pos;
   7566         }
   7567 
   7568         void dumpFileMetadata(FileMetadata info) {
   7569             if (DEBUG) {
   7570                 StringBuilder b = new StringBuilder(128);
   7571 
   7572                 // mode string
   7573                 b.append((info.type == BackupAgent.TYPE_DIRECTORY) ? 'd' : '-');
   7574                 b.append(((info.mode & 0400) != 0) ? 'r' : '-');
   7575                 b.append(((info.mode & 0200) != 0) ? 'w' : '-');
   7576                 b.append(((info.mode & 0100) != 0) ? 'x' : '-');
   7577                 b.append(((info.mode & 0040) != 0) ? 'r' : '-');
   7578                 b.append(((info.mode & 0020) != 0) ? 'w' : '-');
   7579                 b.append(((info.mode & 0010) != 0) ? 'x' : '-');
   7580                 b.append(((info.mode & 0004) != 0) ? 'r' : '-');
   7581                 b.append(((info.mode & 0002) != 0) ? 'w' : '-');
   7582                 b.append(((info.mode & 0001) != 0) ? 'x' : '-');
   7583                 b.append(String.format(" %9d ", info.size));
   7584 
   7585                 Date stamp = new Date(info.mtime);
   7586                 b.append(new SimpleDateFormat("MMM dd HH:mm:ss ").format(stamp));
   7587 
   7588                 b.append(info.packageName);
   7589                 b.append(" :: ");
   7590                 b.append(info.domain);
   7591                 b.append(" :: ");
   7592                 b.append(info.path);
   7593 
   7594                 Slog.i(TAG, b.toString());
   7595             }
   7596         }
   7597         // Consume a tar file header block [sequence] and accumulate the relevant metadata
   7598         FileMetadata readTarHeaders(InputStream instream) throws IOException {
   7599             byte[] block = new byte[512];
   7600             FileMetadata info = null;
   7601 
   7602             boolean gotHeader = readTarHeader(instream, block);
   7603             if (gotHeader) {
   7604                 try {
   7605                     // okay, presume we're okay, and extract the various metadata
   7606                     info = new FileMetadata();
   7607                     info.size = extractRadix(block, 124, 12, 8);
   7608                     info.mtime = extractRadix(block, 136, 12, 8);
   7609                     info.mode = extractRadix(block, 100, 8, 8);
   7610 
   7611                     info.path = extractString(block, 345, 155); // prefix
   7612                     String path = extractString(block, 0, 100);
   7613                     if (path.length() > 0) {
   7614                         if (info.path.length() > 0) info.path += '/';
   7615                         info.path += path;
   7616                     }
   7617 
   7618                     // tar link indicator field: 1 byte at offset 156 in the header.
   7619                     int typeChar = block[156];
   7620                     if (typeChar == 'x') {
   7621                         // pax extended header, so we need to read that
   7622                         gotHeader = readPaxExtendedHeader(instream, info);
   7623                         if (gotHeader) {
   7624                             // and after a pax extended header comes another real header -- read
   7625                             // that to find the real file type
   7626                             gotHeader = readTarHeader(instream, block);
   7627                         }
   7628                         if (!gotHeader) throw new IOException("Bad or missing pax header");
   7629 
   7630                         typeChar = block[156];
   7631                     }
   7632 
   7633                     switch (typeChar) {
   7634                         case '0': info.type = BackupAgent.TYPE_FILE; break;
   7635                         case '5': {
   7636                             info.type = BackupAgent.TYPE_DIRECTORY;
   7637                             if (info.size != 0) {
   7638                                 Slog.w(TAG, "Directory entry with nonzero size in header");
   7639                                 info.size = 0;
   7640                             }
   7641                             break;
   7642                         }
   7643                         case 0: {
   7644                             // presume EOF
   7645                             if (DEBUG) Slog.w(TAG, "Saw type=0 in tar header block, info=" + info);
   7646                             return null;
   7647                         }
   7648                         default: {
   7649                             Slog.e(TAG, "Unknown tar entity type: " + typeChar);
   7650                             throw new IOException("Unknown entity type " + typeChar);
   7651                         }
   7652                     }
   7653 
   7654                     // Parse out the path
   7655                     //
   7656                     // first: apps/shared/unrecognized
   7657                     if (FullBackup.SHARED_PREFIX.regionMatches(0,
   7658                             info.path, 0, FullBackup.SHARED_PREFIX.length())) {
   7659                         // File in shared storage.  !!! TODO: implement this.
   7660                         info.path = info.path.substring(FullBackup.SHARED_PREFIX.length());
   7661                         info.packageName = SHARED_BACKUP_AGENT_PACKAGE;
   7662                         info.domain = FullBackup.SHARED_STORAGE_TOKEN;
   7663                         if (DEBUG) Slog.i(TAG, "File in shared storage: " + info.path);
   7664                     } else if (FullBackup.APPS_PREFIX.regionMatches(0,
   7665                             info.path, 0, FullBackup.APPS_PREFIX.length())) {
   7666                         // App content!  Parse out the package name and domain
   7667 
   7668                         // strip the apps/ prefix
   7669                         info.path = info.path.substring(FullBackup.APPS_PREFIX.length());
   7670 
   7671                         // extract the package name
   7672                         int slash = info.path.indexOf('/');
   7673                         if (slash < 0) throw new IOException("Illegal semantic path in " + info.path);
   7674                         info.packageName = info.path.substring(0, slash);
   7675                         info.path = info.path.substring(slash+1);
   7676 
   7677                         // if it's a manifest or metadata payload we're done, otherwise parse
   7678                         // out the domain into which the file will be restored
   7679                         if (!info.path.equals(BACKUP_MANIFEST_FILENAME)
   7680                                 && !info.path.equals(BACKUP_METADATA_FILENAME)) {
   7681                             slash = info.path.indexOf('/');
   7682                             if (slash < 0) throw new IOException("Illegal semantic path in non-manifest " + info.path);
   7683                             info.domain = info.path.substring(0, slash);
   7684                             info.path = info.path.substring(slash + 1);
   7685                         }
   7686                     }
   7687                 } catch (IOException e) {
   7688                     if (DEBUG) {
   7689                         Slog.e(TAG, "Parse error in header: " + e.getMessage());
   7690                         HEXLOG(block);
   7691                     }
   7692                     throw e;
   7693                 }
   7694             }
   7695             return info;
   7696         }
   7697 
   7698         private void HEXLOG(byte[] block) {
   7699             int offset = 0;
   7700             int todo = block.length;
   7701             StringBuilder buf = new StringBuilder(64);
   7702             while (todo > 0) {
   7703                 buf.append(String.format("%04x   ", offset));
   7704                 int numThisLine = (todo > 16) ? 16 : todo;
   7705                 for (int i = 0; i < numThisLine; i++) {
   7706                     buf.append(String.format("%02x ", block[offset+i]));
   7707                 }
   7708                 Slog.i("hexdump", buf.toString());
   7709                 buf.setLength(0);
   7710                 todo -= numThisLine;
   7711                 offset += numThisLine;
   7712             }
   7713         }
   7714 
   7715         // Read exactly the given number of bytes into a buffer at the stated offset.
   7716         // Returns false if EOF is encountered before the requested number of bytes
   7717         // could be read.
   7718         int readExactly(InputStream in, byte[] buffer, int offset, int size)
   7719                 throws IOException {
   7720             if (size <= 0) throw new IllegalArgumentException("size must be > 0");
   7721 
   7722             int soFar = 0;
   7723             while (soFar < size) {
   7724                 int nRead = in.read(buffer, offset + soFar, size - soFar);
   7725                 if (nRead <= 0) {
   7726                     if (MORE_DEBUG) Slog.w(TAG, "- wanted exactly " + size + " but got only " + soFar);
   7727                     break;
   7728                 }
   7729                 soFar += nRead;
   7730             }
   7731             return soFar;
   7732         }
   7733 
   7734         boolean readTarHeader(InputStream instream, byte[] block) throws IOException {
   7735             final int got = readExactly(instream, block, 0, 512);
   7736             if (got == 0) return false;     // Clean EOF
   7737             if (got < 512) throw new IOException("Unable to read full block header");
   7738             mBytes += 512;
   7739             return true;
   7740         }
   7741 
   7742         // overwrites 'info' fields based on the pax extended header
   7743         boolean readPaxExtendedHeader(InputStream instream, FileMetadata info)
   7744                 throws IOException {
   7745             // We should never see a pax extended header larger than this
   7746             if (info.size > 32*1024) {
   7747                 Slog.w(TAG, "Suspiciously large pax header size " + info.size
   7748                         + " - aborting");
   7749                 throw new IOException("Sanity failure: pax header size " + info.size);
   7750             }
   7751 
   7752             // read whole blocks, not just the content size
   7753             int numBlocks = (int)((info.size + 511) >> 9);
   7754             byte[] data = new byte[numBlocks * 512];
   7755             if (readExactly(instream, data, 0, data.length) < data.length) {
   7756                 throw new IOException("Unable to read full pax header");
   7757             }
   7758             mBytes += data.length;
   7759 
   7760             final int contentSize = (int) info.size;
   7761             int offset = 0;
   7762             do {
   7763                 // extract the line at 'offset'
   7764                 int eol = offset+1;
   7765                 while (eol < contentSize && data[eol] != ' ') eol++;
   7766                 if (eol >= contentSize) {
   7767                     // error: we just hit EOD looking for the end of the size field
   7768                     throw new IOException("Invalid pax data");
   7769                 }
   7770                 // eol points to the space between the count and the key
   7771                 int linelen = (int) extractRadix(data, offset, eol - offset, 10);
   7772                 int key = eol + 1;  // start of key=value
   7773                 eol = offset + linelen - 1; // trailing LF
   7774                 int value;
   7775                 for (value = key+1; data[value] != '=' && value <= eol; value++);
   7776                 if (value > eol) {
   7777                     throw new IOException("Invalid pax declaration");
   7778                 }
   7779 
   7780                 // pax requires that key/value strings be in UTF-8
   7781                 String keyStr = new String(data, key, value-key, "UTF-8");
   7782                 // -1 to strip the trailing LF
   7783                 String valStr = new String(data, value+1, eol-value-1, "UTF-8");
   7784 
   7785                 if ("path".equals(keyStr)) {
   7786                     info.path = valStr;
   7787                 } else if ("size".equals(keyStr)) {
   7788                     info.size = Long.parseLong(valStr);
   7789                 } else {
   7790                     if (DEBUG) Slog.i(TAG, "Unhandled pax key: " + key);
   7791                 }
   7792 
   7793                 offset += linelen;
   7794             } while (offset < contentSize);
   7795 
   7796             return true;
   7797         }
   7798 
   7799         long extractRadix(byte[] data, int offset, int maxChars, int radix)
   7800                 throws IOException {
   7801             long value = 0;
   7802             final int end = offset + maxChars;
   7803             for (int i = offset; i < end; i++) {
   7804                 final byte b = data[i];
   7805                 // Numeric fields in tar can terminate with either NUL or SPC
   7806                 if (b == 0 || b == ' ') break;
   7807                 if (b < '0' || b > ('0' + radix - 1)) {
   7808                     throw new IOException("Invalid number in header: '" + (char)b + "' for radix " + radix);
   7809                 }
   7810                 value = radix * value + (b - '0');
   7811             }
   7812             return value;
   7813         }
   7814 
   7815         String extractString(byte[] data, int offset, int maxChars) throws IOException {
   7816             final int end = offset + maxChars;
   7817             int eos = offset;
   7818             // tar string fields terminate early with a NUL
   7819             while (eos < end && data[eos] != 0) eos++;
   7820             return new String(data, offset, eos-offset, "US-ASCII");
   7821         }
   7822 
   7823         void sendStartRestore() {
   7824             if (mObserver != null) {
   7825                 try {
   7826                     mObserver.onStartRestore();
   7827                 } catch (RemoteException e) {
   7828                     Slog.w(TAG, "full restore observer went away: startRestore");
   7829                     mObserver = null;
   7830                 }
   7831             }
   7832         }
   7833 
   7834         void sendOnRestorePackage(String name) {
   7835             if (mObserver != null) {
   7836                 try {
   7837                     // TODO: use a more user-friendly name string
   7838                     mObserver.onRestorePackage(name);
   7839                 } catch (RemoteException e) {
   7840                     Slog.w(TAG, "full restore observer went away: restorePackage");
   7841                     mObserver = null;
   7842                 }
   7843             }
   7844         }
   7845 
   7846         void sendEndRestore() {
   7847             if (mObserver != null) {
   7848                 try {
   7849                     mObserver.onEndRestore();
   7850                 } catch (RemoteException e) {
   7851                     Slog.w(TAG, "full restore observer went away: endRestore");
   7852                     mObserver = null;
   7853                 }
   7854             }
   7855         }
   7856     }
   7857 
   7858     // ----- Restore handling -----
   7859 
   7860     // Old style: directly match the stored vs on device signature blocks
   7861     static boolean signaturesMatch(Signature[] storedSigs, PackageInfo target) {
   7862         if (target == null) {
   7863             return false;
   7864         }
   7865 
   7866         // If the target resides on the system partition, we allow it to restore
   7867         // data from the like-named package in a restore set even if the signatures
   7868         // do not match.  (Unlike general applications, those flashed to the system
   7869         // partition will be signed with the device's platform certificate, so on
   7870         // different phones the same system app will have different signatures.)
   7871         if ((target.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
   7872             if (MORE_DEBUG) Slog.v(TAG, "System app " + target.packageName + " - skipping sig check");
   7873             return true;
   7874         }
   7875 
   7876         // Allow unsigned apps, but not signed on one device and unsigned on the other
   7877         // !!! TODO: is this the right policy?
   7878         Signature[] deviceSigs = target.signatures;
   7879         if (MORE_DEBUG) Slog.v(TAG, "signaturesMatch(): stored=" + storedSigs
   7880                 + " device=" + deviceSigs);
   7881         if ((storedSigs == null || storedSigs.length == 0)
   7882                 && (deviceSigs == null || deviceSigs.length == 0)) {
   7883             return true;
   7884         }
   7885         if (storedSigs == null || deviceSigs == null) {
   7886             return false;
   7887         }
   7888 
   7889         // !!! TODO: this demands that every stored signature match one
   7890         // that is present on device, and does not demand the converse.
   7891         // Is this this right policy?
   7892         int nStored = storedSigs.length;
   7893         int nDevice = deviceSigs.length;
   7894 
   7895         for (int i=0; i < nStored; i++) {
   7896             boolean match = false;
   7897             for (int j=0; j < nDevice; j++) {
   7898                 if (storedSigs[i].equals(deviceSigs[j])) {
   7899                     match = true;
   7900                     break;
   7901                 }
   7902             }
   7903             if (!match) {
   7904                 return false;
   7905             }
   7906         }
   7907         return true;
   7908     }
   7909 
   7910     // Used by both incremental and full restore
   7911     void restoreWidgetData(String packageName, byte[] widgetData) {
   7912         // Apply the restored widget state and generate the ID update for the app
   7913         // TODO: http://b/22388012
   7914         if (MORE_DEBUG) {
   7915             Slog.i(TAG, "Incorporating restored widget data");
   7916         }
   7917         AppWidgetBackupBridge.restoreWidgetState(packageName, widgetData, UserHandle.USER_SYSTEM);
   7918     }
   7919 
   7920     // *****************************
   7921     // NEW UNIFIED RESTORE IMPLEMENTATION
   7922     // *****************************
   7923 
   7924     // states of the unified-restore state machine
   7925     enum UnifiedRestoreState {
   7926         INITIAL,
   7927         RUNNING_QUEUE,
   7928         RESTORE_KEYVALUE,
   7929         RESTORE_FULL,
   7930         RESTORE_FINISHED,
   7931         FINAL
   7932     }
   7933 
   7934     class PerformUnifiedRestoreTask implements BackupRestoreTask {
   7935         // Transport we're working with to do the restore
   7936         private IBackupTransport mTransport;
   7937 
   7938         // Where per-transport saved state goes
   7939         File mStateDir;
   7940 
   7941         // Restore observer; may be null
   7942         private IRestoreObserver mObserver;
   7943 
   7944         // Token identifying the dataset to the transport
   7945         private long mToken;
   7946 
   7947         // When this is a restore-during-install, this is the token identifying the
   7948         // operation to the Package Manager, and we must ensure that we let it know
   7949         // when we're finished.
   7950         private int mPmToken;
   7951 
   7952         // When this is restore-during-install, we need to tell the package manager
   7953         // whether we actually launched the app, because this affects notifications
   7954         // around externally-visible state transitions.
   7955         private boolean mDidLaunch;
   7956 
   7957         // Is this a whole-system restore, i.e. are we establishing a new ancestral
   7958         // dataset to base future restore-at-install operations from?
   7959         private boolean mIsSystemRestore;
   7960 
   7961         // If this is a single-package restore, what package are we interested in?
   7962         private PackageInfo mTargetPackage;
   7963 
   7964         // In all cases, the calculated list of packages that we are trying to restore
   7965         private List<PackageInfo> mAcceptSet;
   7966 
   7967         // Our bookkeeping about the ancestral dataset
   7968         private PackageManagerBackupAgent mPmAgent;
   7969 
   7970         // Currently-bound backup agent for restore + restoreFinished purposes
   7971         private IBackupAgent mAgent;
   7972 
   7973         // What sort of restore we're doing now
   7974         private RestoreDescription mRestoreDescription;
   7975 
   7976         // The package we're currently restoring
   7977         private PackageInfo mCurrentPackage;
   7978 
   7979         // Widget-related data handled as part of this restore operation
   7980         private byte[] mWidgetData;
   7981 
   7982         // Number of apps restored in this pass
   7983         private int mCount;
   7984 
   7985         // When did we start?
   7986         private long mStartRealtime;
   7987 
   7988         // State machine progress
   7989         private UnifiedRestoreState mState;
   7990 
   7991         // How are things going?
   7992         private int mStatus;
   7993 
   7994         // Done?
   7995         private boolean mFinished;
   7996 
   7997         // Key/value: bookkeeping about staged data and files for agent access
   7998         private File mBackupDataName;
   7999         private File mStageName;
   8000         private File mSavedStateName;
   8001         private File mNewStateName;
   8002         ParcelFileDescriptor mBackupData;
   8003         ParcelFileDescriptor mNewState;
   8004 
   8005         // Invariant: mWakelock is already held, and this task is responsible for
   8006         // releasing it at the end of the restore operation.
   8007         PerformUnifiedRestoreTask(IBackupTransport transport, IRestoreObserver observer,
   8008                 long restoreSetToken, PackageInfo targetPackage, int pmToken,
   8009                 boolean isFullSystemRestore, String[] filterSet) {
   8010             mState = UnifiedRestoreState.INITIAL;
   8011             mStartRealtime = SystemClock.elapsedRealtime();
   8012 
   8013             mTransport = transport;
   8014             mObserver = observer;
   8015             mToken = restoreSetToken;
   8016             mPmToken = pmToken;
   8017             mTargetPackage = targetPackage;
   8018             mIsSystemRestore = isFullSystemRestore;
   8019             mFinished = false;
   8020             mDidLaunch = false;
   8021 
   8022             if (targetPackage != null) {
   8023                 // Single package restore
   8024                 mAcceptSet = new ArrayList<PackageInfo>();
   8025                 mAcceptSet.add(targetPackage);
   8026             } else {
   8027                 // Everything possible, or a target set
   8028                 if (filterSet == null) {
   8029                     // We want everything and a pony
   8030                     List<PackageInfo> apps =
   8031                             PackageManagerBackupAgent.getStorableApplications(mPackageManager);
   8032                     filterSet = packagesToNames(apps);
   8033                     if (DEBUG) {
   8034                         Slog.i(TAG, "Full restore; asking about " + filterSet.length + " apps");
   8035                     }
   8036                 }
   8037 
   8038                 mAcceptSet = new ArrayList<PackageInfo>(filterSet.length);
   8039 
   8040                 // Pro tem, we insist on moving the settings provider package to last place.
   8041                 // Keep track of whether it's in the list, and bump it down if so.  We also
   8042                 // want to do the system package itself first if it's called for.
   8043                 boolean hasSystem = false;
   8044                 boolean hasSettings = false;
   8045                 for (int i = 0; i < filterSet.length; i++) {
   8046                     try {
   8047                         PackageInfo info = mPackageManager.getPackageInfo(filterSet[i], 0);
   8048                         if ("android".equals(info.packageName)) {
   8049                             hasSystem = true;
   8050                             continue;
   8051                         }
   8052                         if (SETTINGS_PACKAGE.equals(info.packageName)) {
   8053                             hasSettings = true;
   8054                             continue;
   8055                         }
   8056 
   8057                         if (appIsEligibleForBackup(info.applicationInfo)) {
   8058                             mAcceptSet.add(info);
   8059                         }
   8060                     } catch (NameNotFoundException e) {
   8061                         // requested package name doesn't exist; ignore it
   8062                     }
   8063                 }
   8064                 if (hasSystem) {
   8065                     try {
   8066                         mAcceptSet.add(0, mPackageManager.getPackageInfo("android", 0));
   8067                     } catch (NameNotFoundException e) {
   8068                         // won't happen; we know a priori that it's valid
   8069                     }
   8070                 }
   8071                 if (hasSettings) {
   8072                     try {
   8073                         mAcceptSet.add(mPackageManager.getPackageInfo(SETTINGS_PACKAGE, 0));
   8074                     } catch (NameNotFoundException e) {
   8075                         // this one is always valid too
   8076                     }
   8077                 }
   8078             }
   8079 
   8080             if (MORE_DEBUG) {
   8081                 Slog.v(TAG, "Restore; accept set size is " + mAcceptSet.size());
   8082                 for (PackageInfo info : mAcceptSet) {
   8083                     Slog.v(TAG, "   " + info.packageName);
   8084                 }
   8085             }
   8086         }
   8087 
   8088         private String[] packagesToNames(List<PackageInfo> apps) {
   8089             final int N = apps.size();
   8090             String[] names = new String[N];
   8091             for (int i = 0; i < N; i++) {
   8092                 names[i] = apps.get(i).packageName;
   8093             }
   8094             return names;
   8095         }
   8096 
   8097         // Execute one tick of whatever state machine the task implements
   8098         @Override
   8099         public void execute() {
   8100             if (MORE_DEBUG) Slog.v(TAG, "*** Executing restore step " + mState);
   8101             switch (mState) {
   8102                 case INITIAL:
   8103                     startRestore();
   8104                     break;
   8105 
   8106                 case RUNNING_QUEUE:
   8107                     dispatchNextRestore();
   8108                     break;
   8109 
   8110                 case RESTORE_KEYVALUE:
   8111                     restoreKeyValue();
   8112                     break;
   8113 
   8114                 case RESTORE_FULL:
   8115                     restoreFull();
   8116                     break;
   8117 
   8118                 case RESTORE_FINISHED:
   8119                     restoreFinished();
   8120                     break;
   8121 
   8122                 case FINAL:
   8123                     if (!mFinished) finalizeRestore();
   8124                     else {
   8125                         Slog.e(TAG, "Duplicate finish");
   8126                     }
   8127                     mFinished = true;
   8128                     break;
   8129             }
   8130         }
   8131 
   8132         /*
   8133          * SKETCH OF OPERATION
   8134          *
   8135          * create one of these PerformUnifiedRestoreTask objects, telling it which
   8136          * dataset & transport to address, and then parameters within the restore
   8137          * operation: single target package vs many, etc.
   8138          *
   8139          * 1. transport.startRestore(token, list-of-packages).  If we need @pm@  it is
   8140          * always placed first and the settings provider always placed last [for now].
   8141          *
   8142          * 1a [if we needed @pm@ then nextRestorePackage() and restore the PMBA inline]
   8143          *
   8144          *   [ state change => RUNNING_QUEUE ]
   8145          *
   8146          * NOW ITERATE:
   8147          *
   8148          * { 3. t.nextRestorePackage()
   8149          *   4. does the metadata for this package allow us to restore it?
   8150          *      does the on-disk app permit us to restore it? [re-check allowBackup etc]
   8151          *   5. is this a key/value dataset?  => key/value agent restore
   8152          *       [ state change => RESTORE_KEYVALUE ]
   8153          *       5a. spin up agent
   8154          *       5b. t.getRestoreData() to stage it properly
   8155          *       5c. call into agent to perform restore
   8156          *       5d. tear down agent
   8157          *       [ state change => RUNNING_QUEUE ]
   8158          *
   8159          *   6. else it's a stream dataset:
   8160          *       [ state change => RESTORE_FULL ]
   8161          *       6a. instantiate the engine for a stream restore: engine handles agent lifecycles
   8162          *       6b. spin off engine runner on separate thread
   8163          *       6c. ITERATE getNextFullRestoreDataChunk() and copy data to engine runner socket
   8164          *       [ state change => RUNNING_QUEUE ]
   8165          * }
   8166          *
   8167          *   [ state change => FINAL ]
   8168          *
   8169          * 7. t.finishRestore(), release wakelock, etc.
   8170          *
   8171          *
   8172          */
   8173 
   8174         // state INITIAL : set up for the restore and read the metadata if necessary
   8175         private  void startRestore() {
   8176             sendStartRestore(mAcceptSet.size());
   8177 
   8178             // If we're starting a full-system restore, set up to begin widget ID remapping
   8179             if (mIsSystemRestore) {
   8180                 // TODO: http://b/22388012
   8181                 AppWidgetBackupBridge.restoreStarting(UserHandle.USER_SYSTEM);
   8182             }
   8183 
   8184             try {
   8185                 String transportDir = mTransport.transportDirName();
   8186                 mStateDir = new File(mBaseStateDir, transportDir);
   8187 
   8188                 // Fetch the current metadata from the dataset first
   8189                 PackageInfo pmPackage = new PackageInfo();
   8190                 pmPackage.packageName = PACKAGE_MANAGER_SENTINEL;
   8191                 mAcceptSet.add(0, pmPackage);
   8192 
   8193                 PackageInfo[] packages = mAcceptSet.toArray(new PackageInfo[0]);
   8194                 mStatus = mTransport.startRestore(mToken, packages);
   8195                 if (mStatus != BackupTransport.TRANSPORT_OK) {
   8196                     Slog.e(TAG, "Transport error " + mStatus + "; no restore possible");
   8197                     mStatus = BackupTransport.TRANSPORT_ERROR;
   8198                     executeNextState(UnifiedRestoreState.FINAL);
   8199                     return;
   8200                 }
   8201 
   8202                 RestoreDescription desc = mTransport.nextRestorePackage();
   8203                 if (desc == null) {
   8204                     Slog.e(TAG, "No restore metadata available; halting");
   8205                     mStatus = BackupTransport.TRANSPORT_ERROR;
   8206                     executeNextState(UnifiedRestoreState.FINAL);
   8207                     return;
   8208                 }
   8209                 if (!PACKAGE_MANAGER_SENTINEL.equals(desc.getPackageName())) {
   8210                     Slog.e(TAG, "Required metadata but got " + desc.getPackageName());
   8211                     mStatus = BackupTransport.TRANSPORT_ERROR;
   8212                     executeNextState(UnifiedRestoreState.FINAL);
   8213                     return;
   8214                 }
   8215 
   8216                 // Pull the Package Manager metadata from the restore set first
   8217                 mCurrentPackage = new PackageInfo();
   8218                 mCurrentPackage.packageName = PACKAGE_MANAGER_SENTINEL;
   8219                 mPmAgent = new PackageManagerBackupAgent(mPackageManager, null);
   8220                 mAgent = IBackupAgent.Stub.asInterface(mPmAgent.onBind());
   8221                 if (MORE_DEBUG) {
   8222                     Slog.v(TAG, "initiating restore for PMBA");
   8223                 }
   8224                 initiateOneRestore(mCurrentPackage, 0);
   8225                 // The PM agent called operationComplete() already, because our invocation
   8226                 // of it is process-local and therefore synchronous.  That means that the
   8227                 // next-state message (RUNNING_QUEUE) is already enqueued.  Only if we're
   8228                 // unable to proceed with running the queue do we remove that pending
   8229                 // message and jump straight to the FINAL state.  Because this was
   8230                 // synchronous we also know that we should cancel the pending timeout
   8231                 // message.
   8232                 mBackupHandler.removeMessages(MSG_TIMEOUT);
   8233 
   8234                 // Verify that the backup set includes metadata.  If not, we can't do
   8235                 // signature/version verification etc, so we simply do not proceed with
   8236                 // the restore operation.
   8237                 if (!mPmAgent.hasMetadata()) {
   8238                     Slog.e(TAG, "No restore metadata available, so not restoring");
   8239                     EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
   8240                             PACKAGE_MANAGER_SENTINEL,
   8241                             "Package manager restore metadata missing");
   8242                     mStatus = BackupTransport.TRANSPORT_ERROR;
   8243                     mBackupHandler.removeMessages(MSG_BACKUP_RESTORE_STEP, this);
   8244                     executeNextState(UnifiedRestoreState.FINAL);
   8245                     return;
   8246                 }
   8247 
   8248                 // Success; cache the metadata and continue as expected with the
   8249                 // next state already enqueued
   8250 
   8251             } catch (Exception e) {
   8252                 // If we lost the transport at any time, halt
   8253                 Slog.e(TAG, "Unable to contact transport for restore: " + e.getMessage());
   8254                 mStatus = BackupTransport.TRANSPORT_ERROR;
   8255                 mBackupHandler.removeMessages(MSG_BACKUP_RESTORE_STEP, this);
   8256                 executeNextState(UnifiedRestoreState.FINAL);
   8257                 return;
   8258             }
   8259         }
   8260 
   8261         // state RUNNING_QUEUE : figure out what the next thing to be restored is,
   8262         // and fire the appropriate next step
   8263         private void dispatchNextRestore() {
   8264             UnifiedRestoreState nextState = UnifiedRestoreState.FINAL;
   8265             try {
   8266                 mRestoreDescription = mTransport.nextRestorePackage();
   8267                 final String pkgName = (mRestoreDescription != null)
   8268                         ? mRestoreDescription.getPackageName() : null;
   8269                 if (pkgName == null) {
   8270                     Slog.e(TAG, "Failure getting next package name");
   8271                     EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
   8272                     nextState = UnifiedRestoreState.FINAL;
   8273                     return;
   8274                 } else if (mRestoreDescription == RestoreDescription.NO_MORE_PACKAGES) {
   8275                     // Yay we've reached the end cleanly
   8276                     if (DEBUG) {
   8277                         Slog.v(TAG, "No more packages; finishing restore");
   8278                     }
   8279                     int millis = (int) (SystemClock.elapsedRealtime() - mStartRealtime);
   8280                     EventLog.writeEvent(EventLogTags.RESTORE_SUCCESS, mCount, millis);
   8281                     nextState = UnifiedRestoreState.FINAL;
   8282                     return;
   8283                 }
   8284 
   8285                 if (DEBUG) {
   8286                     Slog.i(TAG, "Next restore package: " + mRestoreDescription);
   8287                 }
   8288                 sendOnRestorePackage(pkgName);
   8289 
   8290                 Metadata metaInfo = mPmAgent.getRestoredMetadata(pkgName);
   8291                 if (metaInfo == null) {
   8292                     Slog.e(TAG, "No metadata for " + pkgName);
   8293                     EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, pkgName,
   8294                             "Package metadata missing");
   8295                     nextState = UnifiedRestoreState.RUNNING_QUEUE;
   8296                     return;
   8297                 }
   8298 
   8299                 try {
   8300                     mCurrentPackage = mPackageManager.getPackageInfo(
   8301                             pkgName, PackageManager.GET_SIGNATURES);
   8302                 } catch (NameNotFoundException e) {
   8303                     // Whoops, we thought we could restore this package but it
   8304                     // turns out not to be present.  Skip it.
   8305                     Slog.e(TAG, "Package not present: " + pkgName);
   8306                     EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, pkgName,
   8307                             "Package missing on device");
   8308                     nextState = UnifiedRestoreState.RUNNING_QUEUE;
   8309                     return;
   8310                 }
   8311 
   8312                 if (metaInfo.versionCode > mCurrentPackage.versionCode) {
   8313                     // Data is from a "newer" version of the app than we have currently
   8314                     // installed.  If the app has not declared that it is prepared to
   8315                     // handle this case, we do not attempt the restore.
   8316                     if ((mCurrentPackage.applicationInfo.flags
   8317                             & ApplicationInfo.FLAG_RESTORE_ANY_VERSION) == 0) {
   8318                         String message = "Version " + metaInfo.versionCode
   8319                                 + " > installed version " + mCurrentPackage.versionCode;
   8320                         Slog.w(TAG, "Package " + pkgName + ": " + message);
   8321                         EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
   8322                                 pkgName, message);
   8323                         nextState = UnifiedRestoreState.RUNNING_QUEUE;
   8324                         return;
   8325                     } else {
   8326                         if (DEBUG) Slog.v(TAG, "Version " + metaInfo.versionCode
   8327                                 + " > installed " + mCurrentPackage.versionCode
   8328                                 + " but restoreAnyVersion");
   8329                     }
   8330                 }
   8331 
   8332                 if (MORE_DEBUG) Slog.v(TAG, "Package " + pkgName
   8333                         + " restore version [" + metaInfo.versionCode
   8334                         + "] is compatible with installed version ["
   8335                         + mCurrentPackage.versionCode + "]");
   8336 
   8337                 // Reset per-package preconditions and fire the appropriate next state
   8338                 mWidgetData = null;
   8339                 final int type = mRestoreDescription.getDataType();
   8340                 if (type == RestoreDescription.TYPE_KEY_VALUE) {
   8341                     nextState = UnifiedRestoreState.RESTORE_KEYVALUE;
   8342                 } else if (type == RestoreDescription.TYPE_FULL_STREAM) {
   8343                     nextState = UnifiedRestoreState.RESTORE_FULL;
   8344                 } else {
   8345                     // Unknown restore type; ignore this package and move on
   8346                     Slog.e(TAG, "Unrecognized restore type " + type);
   8347                     nextState = UnifiedRestoreState.RUNNING_QUEUE;
   8348                     return;
   8349                 }
   8350             } catch (Exception e) {
   8351                 Slog.e(TAG, "Can't get next restore target from transport; halting: "
   8352                         + e.getMessage());
   8353                 EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
   8354                 nextState = UnifiedRestoreState.FINAL;
   8355                 return;
   8356             } finally {
   8357                 executeNextState(nextState);
   8358             }
   8359         }
   8360 
   8361         // state RESTORE_KEYVALUE : restore one package via key/value API set
   8362         private void restoreKeyValue() {
   8363             // Initiating the restore will pass responsibility for the state machine's
   8364             // progress to the agent callback, so we do not always execute the
   8365             // next state here.
   8366             final String packageName = mCurrentPackage.packageName;
   8367             // Validate some semantic requirements that apply in this way
   8368             // only to the key/value restore API flow
   8369             if (mCurrentPackage.applicationInfo.backupAgentName == null
   8370                     || "".equals(mCurrentPackage.applicationInfo.backupAgentName)) {
   8371                 if (MORE_DEBUG) {
   8372                     Slog.i(TAG, "Data exists for package " + packageName
   8373                             + " but app has no agent; skipping");
   8374                 }
   8375                 EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
   8376                         "Package has no agent");
   8377                 executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
   8378                 return;
   8379             }
   8380 
   8381             Metadata metaInfo = mPmAgent.getRestoredMetadata(packageName);
   8382             if (!BackupUtils.signaturesMatch(metaInfo.sigHashes, mCurrentPackage)) {
   8383                 Slog.w(TAG, "Signature mismatch restoring " + packageName);
   8384                 EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
   8385                         "Signature mismatch");
   8386                 executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
   8387                 return;
   8388             }
   8389 
   8390             // Good to go!  Set up and bind the agent...
   8391             mAgent = bindToAgentSynchronous(
   8392                     mCurrentPackage.applicationInfo,
   8393                     IApplicationThread.BACKUP_MODE_INCREMENTAL);
   8394             if (mAgent == null) {
   8395                 Slog.w(TAG, "Can't find backup agent for " + packageName);
   8396                 EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
   8397                         "Restore agent missing");
   8398                 executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
   8399                 return;
   8400             }
   8401 
   8402             // Whatever happens next, we've launched the target app now; remember that.
   8403             mDidLaunch = true;
   8404 
   8405             // And then finally start the restore on this agent
   8406             try {
   8407                 initiateOneRestore(mCurrentPackage, metaInfo.versionCode);
   8408                 ++mCount;
   8409             } catch (Exception e) {
   8410                 Slog.e(TAG, "Error when attempting restore: " + e.toString());
   8411                 keyValueAgentErrorCleanup();
   8412                 executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
   8413             }
   8414         }
   8415 
   8416         // Guts of a key/value restore operation
   8417         void initiateOneRestore(PackageInfo app, int appVersionCode) {
   8418             final String packageName = app.packageName;
   8419 
   8420             if (DEBUG) Slog.d(TAG, "initiateOneRestore packageName=" + packageName);
   8421 
   8422             // !!! TODO: get the dirs from the transport
   8423             mBackupDataName = new File(mDataDir, packageName + ".restore");
   8424             mStageName = new File(mDataDir, packageName + ".stage");
   8425             mNewStateName = new File(mStateDir, packageName + ".new");
   8426             mSavedStateName = new File(mStateDir, packageName);
   8427 
   8428             // don't stage the 'android' package where the wallpaper data lives.  this is
   8429             // an optimization: we know there's no widget data hosted/published by that
   8430             // package, and this way we avoid doing a spurious copy of MB-sized wallpaper
   8431             // data following the download.
   8432             boolean staging = !packageName.equals("android");
   8433             ParcelFileDescriptor stage;
   8434             File downloadFile = (staging) ? mStageName : mBackupDataName;
   8435 
   8436             final int token = generateToken();
   8437             try {
   8438                 // Run the transport's restore pass
   8439                 stage = ParcelFileDescriptor.open(downloadFile,
   8440                         ParcelFileDescriptor.MODE_READ_WRITE |
   8441                         ParcelFileDescriptor.MODE_CREATE |
   8442                         ParcelFileDescriptor.MODE_TRUNCATE);
   8443 
   8444                 if (mTransport.getRestoreData(stage) != BackupTransport.TRANSPORT_OK) {
   8445                     // Transport-level failure, so we wind everything up and
   8446                     // terminate the restore operation.
   8447                     Slog.e(TAG, "Error getting restore data for " + packageName);
   8448                     EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
   8449                     stage.close();
   8450                     downloadFile.delete();
   8451                     executeNextState(UnifiedRestoreState.FINAL);
   8452                     return;
   8453                 }
   8454 
   8455                 // We have the data from the transport. Now we extract and strip
   8456                 // any per-package metadata (typically widget-related information)
   8457                 // if appropriate
   8458                 if (staging) {
   8459                     stage.close();
   8460                     stage = ParcelFileDescriptor.open(downloadFile,
   8461                             ParcelFileDescriptor.MODE_READ_ONLY);
   8462 
   8463                     mBackupData = ParcelFileDescriptor.open(mBackupDataName,
   8464                             ParcelFileDescriptor.MODE_READ_WRITE |
   8465                             ParcelFileDescriptor.MODE_CREATE |
   8466                             ParcelFileDescriptor.MODE_TRUNCATE);
   8467 
   8468                     BackupDataInput in = new BackupDataInput(stage.getFileDescriptor());
   8469                     BackupDataOutput out = new BackupDataOutput(mBackupData.getFileDescriptor());
   8470                     byte[] buffer = new byte[8192]; // will grow when needed
   8471                     while (in.readNextHeader()) {
   8472                         final String key = in.getKey();
   8473                         final int size = in.getDataSize();
   8474 
   8475                         // is this a special key?
   8476                         if (key.equals(KEY_WIDGET_STATE)) {
   8477                             if (DEBUG) {
   8478                                 Slog.i(TAG, "Restoring widget state for " + packageName);
   8479                             }
   8480                             mWidgetData = new byte[size];
   8481                             in.readEntityData(mWidgetData, 0, size);
   8482                         } else {
   8483                             if (size > buffer.length) {
   8484                                 buffer = new byte[size];
   8485                             }
   8486                             in.readEntityData(buffer, 0, size);
   8487                             out.writeEntityHeader(key, size);
   8488                             out.writeEntityData(buffer, size);
   8489                         }
   8490                     }
   8491 
   8492                     mBackupData.close();
   8493                 }
   8494 
   8495                 // Okay, we have the data.  Now have the agent do the restore.
   8496                 stage.close();
   8497 
   8498                 mBackupData = ParcelFileDescriptor.open(mBackupDataName,
   8499                         ParcelFileDescriptor.MODE_READ_ONLY);
   8500 
   8501                 mNewState = ParcelFileDescriptor.open(mNewStateName,
   8502                         ParcelFileDescriptor.MODE_READ_WRITE |
   8503                         ParcelFileDescriptor.MODE_CREATE |
   8504                         ParcelFileDescriptor.MODE_TRUNCATE);
   8505 
   8506                 // Kick off the restore, checking for hung agents.  The timeout or
   8507                 // the operationComplete() callback will schedule the next step,
   8508                 // so we do not do that here.
   8509                 prepareOperationTimeout(token, TIMEOUT_RESTORE_INTERVAL, this);
   8510                 mAgent.doRestore(mBackupData, appVersionCode, mNewState,
   8511                         token, mBackupManagerBinder);
   8512             } catch (Exception e) {
   8513                 Slog.e(TAG, "Unable to call app for restore: " + packageName, e);
   8514                 EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
   8515                         packageName, e.toString());
   8516                 keyValueAgentErrorCleanup();    // clears any pending timeout messages as well
   8517 
   8518                 // After a restore failure we go back to running the queue.  If there
   8519                 // are no more packages to be restored that will be handled by the
   8520                 // next step.
   8521                 executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
   8522             }
   8523         }
   8524 
   8525         // state RESTORE_FULL : restore one package via streaming engine
   8526         private void restoreFull() {
   8527             // None of this can run on the work looper here, so we spin asynchronous
   8528             // work like this:
   8529             //
   8530             //   StreamFeederThread: read data from mTransport.getNextFullRestoreDataChunk()
   8531             //                       write it into the pipe to the engine
   8532             //   EngineThread: FullRestoreEngine thread communicating with the target app
   8533             //
   8534             // When finished, StreamFeederThread executes next state as appropriate on the
   8535             // backup looper, and the overall unified restore task resumes
   8536             try {
   8537                 StreamFeederThread feeder = new StreamFeederThread();
   8538                 if (MORE_DEBUG) {
   8539                     Slog.i(TAG, "Spinning threads for stream restore of "
   8540                             + mCurrentPackage.packageName);
   8541                 }
   8542                 new Thread(feeder, "unified-stream-feeder").start();
   8543 
   8544                 // At this point the feeder is responsible for advancing the restore
   8545                 // state, so we're done here.
   8546             } catch (IOException e) {
   8547                 // Unable to instantiate the feeder thread -- we need to bail on the
   8548                 // current target.  We haven't asked the transport for data yet, though,
   8549                 // so we can do that simply by going back to running the restore queue.
   8550                 Slog.e(TAG, "Unable to construct pipes for stream restore!");
   8551                 executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
   8552             }
   8553         }
   8554 
   8555         // state RESTORE_FINISHED : provide the "no more data" signpost callback at the end
   8556         private void restoreFinished() {
   8557             try {
   8558                 final int token = generateToken();
   8559                 prepareOperationTimeout(token, TIMEOUT_RESTORE_FINISHED_INTERVAL, this);
   8560                 mAgent.doRestoreFinished(token, mBackupManagerBinder);
   8561                 // If we get this far, the callback or timeout will schedule the
   8562                 // next restore state, so we're done
   8563             } catch (Exception e) {
   8564                 final String packageName = mCurrentPackage.packageName;
   8565                 Slog.e(TAG, "Unable to finalize restore of " + packageName);
   8566                 EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
   8567                         packageName, e.toString());
   8568                 keyValueAgentErrorCleanup();
   8569                 executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
   8570             }
   8571         }
   8572 
   8573         class StreamFeederThread extends RestoreEngine implements Runnable, BackupRestoreTask {
   8574             final String TAG = "StreamFeederThread";
   8575             FullRestoreEngine mEngine;
   8576             EngineThread mEngineThread;
   8577 
   8578             // pipe through which we read data from the transport. [0] read, [1] write
   8579             ParcelFileDescriptor[] mTransportPipes;
   8580 
   8581             // pipe through which the engine will read data.  [0] read, [1] write
   8582             ParcelFileDescriptor[] mEnginePipes;
   8583 
   8584             public StreamFeederThread() throws IOException {
   8585                 mTransportPipes = ParcelFileDescriptor.createPipe();
   8586                 mEnginePipes = ParcelFileDescriptor.createPipe();
   8587                 setRunning(true);
   8588             }
   8589 
   8590             @Override
   8591             public void run() {
   8592                 UnifiedRestoreState nextState = UnifiedRestoreState.RUNNING_QUEUE;
   8593                 int status = BackupTransport.TRANSPORT_OK;
   8594 
   8595                 EventLog.writeEvent(EventLogTags.FULL_RESTORE_PACKAGE,
   8596                         mCurrentPackage.packageName);
   8597 
   8598                 mEngine = new FullRestoreEngine(this, null, mCurrentPackage, false, false);
   8599                 mEngineThread = new EngineThread(mEngine, mEnginePipes[0]);
   8600 
   8601                 ParcelFileDescriptor eWriteEnd = mEnginePipes[1];
   8602                 ParcelFileDescriptor tReadEnd = mTransportPipes[0];
   8603                 ParcelFileDescriptor tWriteEnd = mTransportPipes[1];
   8604 
   8605                 int bufferSize = 32 * 1024;
   8606                 byte[] buffer = new byte[bufferSize];
   8607                 FileOutputStream engineOut = new FileOutputStream(eWriteEnd.getFileDescriptor());
   8608                 FileInputStream transportIn = new FileInputStream(tReadEnd.getFileDescriptor());
   8609 
   8610                 // spin up the engine and start moving data to it
   8611                 new Thread(mEngineThread, "unified-restore-engine").start();
   8612 
   8613                 try {
   8614                     while (status == BackupTransport.TRANSPORT_OK) {
   8615                         // have the transport write some of the restoring data to us
   8616                         int result = mTransport.getNextFullRestoreDataChunk(tWriteEnd);
   8617                         if (result > 0) {
   8618                             // The transport wrote this many bytes of restore data to the
   8619                             // pipe, so pass it along to the engine.
   8620                             if (MORE_DEBUG) {
   8621                                 Slog.v(TAG, "  <- transport provided chunk size " + result);
   8622                             }
   8623                             if (result > bufferSize) {
   8624                                 bufferSize = result;
   8625                                 buffer = new byte[bufferSize];
   8626                             }
   8627                             int toCopy = result;
   8628                             while (toCopy > 0) {
   8629                                 int n = transportIn.read(buffer, 0, toCopy);
   8630                                 engineOut.write(buffer, 0, n);
   8631                                 toCopy -= n;
   8632                                 if (MORE_DEBUG) {
   8633                                     Slog.v(TAG, "  -> wrote " + n + " to engine, left=" + toCopy);
   8634                                 }
   8635                             }
   8636                         } else if (result == BackupTransport.NO_MORE_DATA) {
   8637                             // Clean finish.  Wind up and we're done!
   8638                             if (MORE_DEBUG) {
   8639                                 Slog.i(TAG, "Got clean full-restore EOF for "
   8640                                         + mCurrentPackage.packageName);
   8641                             }
   8642                             status = BackupTransport.TRANSPORT_OK;
   8643                             break;
   8644                         } else {
   8645                             // Transport reported some sort of failure; the fall-through
   8646                             // handling will deal properly with that.
   8647                             Slog.e(TAG, "Error " + result + " streaming restore for "
   8648                                     + mCurrentPackage.packageName);
   8649                             EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
   8650                             status = result;
   8651                         }
   8652                     }
   8653                     if (MORE_DEBUG) Slog.v(TAG, "Done copying to engine, falling through");
   8654                 } catch (IOException e) {
   8655                     // We lost our ability to communicate via the pipes.  That's worrying
   8656                     // but potentially recoverable; abandon this package's restore but
   8657                     // carry on with the next restore target.
   8658                     Slog.e(TAG, "Unable to route data for restore");
   8659                     EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
   8660                             mCurrentPackage.packageName, "I/O error on pipes");
   8661                     status = BackupTransport.AGENT_ERROR;
   8662                 } catch (Exception e) {
   8663                     // The transport threw; terminate the whole operation.  Closing
   8664                     // the sockets will wake up the engine and it will then tidy up the
   8665                     // remote end.
   8666                     Slog.e(TAG, "Transport failed during restore: " + e.getMessage());
   8667                     EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
   8668                     status = BackupTransport.TRANSPORT_ERROR;
   8669                 } finally {
   8670                     // Close the transport pipes and *our* end of the engine pipe,
   8671                     // but leave the engine thread's end open so that it properly
   8672                     // hits EOF and winds up its operations.
   8673                     IoUtils.closeQuietly(mEnginePipes[1]);
   8674                     IoUtils.closeQuietly(mTransportPipes[0]);
   8675                     IoUtils.closeQuietly(mTransportPipes[1]);
   8676 
   8677                     // Don't proceed until the engine has wound up operations
   8678                     mEngineThread.waitForResult();
   8679 
   8680                     // Now we're really done with this one too
   8681                     IoUtils.closeQuietly(mEnginePipes[0]);
   8682 
   8683                     // In all cases we want to remember whether we launched
   8684                     // the target app as part of our work so far.
   8685                     mDidLaunch = (mEngine.getAgent() != null);
   8686 
   8687                     // If we hit a transport-level error, we are done with everything;
   8688                     // if we hit an agent error we just go back to running the queue.
   8689                     if (status == BackupTransport.TRANSPORT_OK) {
   8690                         // Clean finish means we issue the restore-finished callback
   8691                         nextState = UnifiedRestoreState.RESTORE_FINISHED;
   8692 
   8693                         // the engine bound the target's agent, so recover that binding
   8694                         // to use for the callback.
   8695                         mAgent = mEngine.getAgent();
   8696 
   8697                         // and the restored widget data, if any
   8698                         mWidgetData = mEngine.getWidgetData();
   8699                     } else {
   8700                         // Something went wrong somewhere.  Whether it was at the transport
   8701                         // level is immaterial; we need to tell the transport to bail
   8702                         try {
   8703                             mTransport.abortFullRestore();
   8704                         } catch (Exception e) {
   8705                             // transport itself is dead; make sure we handle this as a
   8706                             // fatal error
   8707                             Slog.e(TAG, "Transport threw from abortFullRestore: " + e.getMessage());
   8708                             status = BackupTransport.TRANSPORT_ERROR;
   8709                         }
   8710 
   8711                         // We also need to wipe the current target's data, as it's probably
   8712                         // in an incoherent state.
   8713                         clearApplicationDataSynchronous(mCurrentPackage.packageName);
   8714 
   8715                         // Schedule the next state based on the nature of our failure
   8716                         if (status == BackupTransport.TRANSPORT_ERROR) {
   8717                             nextState = UnifiedRestoreState.FINAL;
   8718                         } else {
   8719                             nextState = UnifiedRestoreState.RUNNING_QUEUE;
   8720                         }
   8721                     }
   8722                     executeNextState(nextState);
   8723                     setRunning(false);
   8724                 }
   8725             }
   8726 
   8727             // BackupRestoreTask interface, specifically for timeout handling
   8728 
   8729             @Override
   8730             public void execute() { /* intentionally empty */ }
   8731 
   8732             @Override
   8733             public void operationComplete(long result) { /* intentionally empty */ }
   8734 
   8735             // The app has timed out handling a restoring file
   8736             @Override
   8737             public void handleTimeout() {
   8738                 if (DEBUG) {
   8739                     Slog.w(TAG, "Full-data restore target timed out; shutting down");
   8740                 }
   8741                 mEngineThread.handleTimeout();
   8742 
   8743                 IoUtils.closeQuietly(mEnginePipes[1]);
   8744                 mEnginePipes[1] = null;
   8745                 IoUtils.closeQuietly(mEnginePipes[0]);
   8746                 mEnginePipes[0] = null;
   8747             }
   8748         }
   8749 
   8750         class EngineThread implements Runnable {
   8751             FullRestoreEngine mEngine;
   8752             FileInputStream mEngineStream;
   8753 
   8754             EngineThread(FullRestoreEngine engine, ParcelFileDescriptor engineSocket) {
   8755                 mEngine = engine;
   8756                 engine.setRunning(true);
   8757                 // We *do* want this FileInputStream to own the underlying fd, so that
   8758                 // when we are finished with it, it closes this end of the pipe in a way
   8759                 // that signals its other end.
   8760                 mEngineStream = new FileInputStream(engineSocket.getFileDescriptor(), true);
   8761             }
   8762 
   8763             public boolean isRunning() {
   8764                 return mEngine.isRunning();
   8765             }
   8766 
   8767             public int waitForResult() {
   8768                 return mEngine.waitForResult();
   8769             }
   8770 
   8771             @Override
   8772             public void run() {
   8773                 try {
   8774                     while (mEngine.isRunning()) {
   8775                         // Tell it to be sure to leave the agent instance up after finishing
   8776                         mEngine.restoreOneFile(mEngineStream, false);
   8777                     }
   8778                 } finally {
   8779                     // Because mEngineStream adopted its underlying FD, this also
   8780                     // closes this end of the pipe.
   8781                     IoUtils.closeQuietly(mEngineStream);
   8782                 }
   8783             }
   8784 
   8785             public void handleTimeout() {
   8786                 IoUtils.closeQuietly(mEngineStream);
   8787                 mEngine.handleTimeout();
   8788             }
   8789         }
   8790 
   8791         // state FINAL : tear everything down and we're done.
   8792         private void finalizeRestore() {
   8793             if (MORE_DEBUG) Slog.d(TAG, "finishing restore mObserver=" + mObserver);
   8794 
   8795             try {
   8796                 mTransport.finishRestore();
   8797             } catch (Exception e) {
   8798                 Slog.e(TAG, "Error finishing restore", e);
   8799             }
   8800 
   8801             // Tell the observer we're done
   8802             if (mObserver != null) {
   8803                 try {
   8804                     mObserver.restoreFinished(mStatus);
   8805                 } catch (RemoteException e) {
   8806                     Slog.d(TAG, "Restore observer died at restoreFinished");
   8807                 }
   8808             }
   8809 
   8810             // Clear any ongoing session timeout.
   8811             mBackupHandler.removeMessages(MSG_RESTORE_TIMEOUT);
   8812 
   8813             // If we have a PM token, we must under all circumstances be sure to
   8814             // handshake when we've finished.
   8815             if (mPmToken > 0) {
   8816                 if (MORE_DEBUG) Slog.v(TAG, "finishing PM token " + mPmToken);
   8817                 try {
   8818                     mPackageManagerBinder.finishPackageInstall(mPmToken, mDidLaunch);
   8819                 } catch (RemoteException e) { /* can't happen */ }
   8820             } else {
   8821                 // We were invoked via an active restore session, not by the Package
   8822                 // Manager, so start up the session timeout again.
   8823                 mBackupHandler.sendEmptyMessageDelayed(MSG_RESTORE_TIMEOUT,
   8824                         TIMEOUT_RESTORE_INTERVAL);
   8825             }
   8826 
   8827             // Kick off any work that may be needed regarding app widget restores
   8828             // TODO: http://b/22388012
   8829             AppWidgetBackupBridge.restoreFinished(UserHandle.USER_SYSTEM);
   8830 
   8831             // If this was a full-system restore, record the ancestral
   8832             // dataset information
   8833             if (mIsSystemRestore && mPmAgent != null) {
   8834                 mAncestralPackages = mPmAgent.getRestoredPackages();
   8835                 mAncestralToken = mToken;
   8836                 writeRestoreTokens();
   8837             }
   8838 
   8839             // done; we can finally release the wakelock and be legitimately done.
   8840             Slog.i(TAG, "Restore complete.");
   8841             mWakelock.release();
   8842         }
   8843 
   8844         void keyValueAgentErrorCleanup() {
   8845             // If the agent fails restore, it might have put the app's data
   8846             // into an incoherent state.  For consistency we wipe its data
   8847             // again in this case before continuing with normal teardown
   8848             clearApplicationDataSynchronous(mCurrentPackage.packageName);
   8849             keyValueAgentCleanup();
   8850         }
   8851 
   8852         // TODO: clean up naming; this is now used at finish by both k/v and stream restores
   8853         void keyValueAgentCleanup() {
   8854             mBackupDataName.delete();
   8855             mStageName.delete();
   8856             try { if (mBackupData != null) mBackupData.close(); } catch (IOException e) {}
   8857             try { if (mNewState != null) mNewState.close(); } catch (IOException e) {}
   8858             mBackupData = mNewState = null;
   8859 
   8860             // if everything went okay, remember the recorded state now
   8861             //
   8862             // !!! TODO: the restored data could be migrated on the server
   8863             // side into the current dataset.  In that case the new state file
   8864             // we just created would reflect the data already extant in the
   8865             // backend, so there'd be nothing more to do.  Until that happens,
   8866             // however, we need to make sure that we record the data to the
   8867             // current backend dataset.  (Yes, this means shipping the data over
   8868             // the wire in both directions.  That's bad, but consistency comes
   8869             // first, then efficiency.)  Once we introduce server-side data
   8870             // migration to the newly-restored device's dataset, we will change
   8871             // the following from a discard of the newly-written state to the
   8872             // "correct" operation of renaming into the canonical state blob.
   8873             mNewStateName.delete();                      // TODO: remove; see above comment
   8874             //mNewStateName.renameTo(mSavedStateName);   // TODO: replace with this
   8875 
   8876             // If this wasn't the PM pseudopackage, tear down the agent side
   8877             if (mCurrentPackage.applicationInfo != null) {
   8878                 // unbind and tidy up even on timeout or failure
   8879                 try {
   8880                     mActivityManager.unbindBackupAgent(mCurrentPackage.applicationInfo);
   8881 
   8882                     // The agent was probably running with a stub Application object,
   8883                     // which isn't a valid run mode for the main app logic.  Shut
   8884                     // down the app so that next time it's launched, it gets the
   8885                     // usual full initialization.  Note that this is only done for
   8886                     // full-system restores: when a single app has requested a restore,
   8887                     // it is explicitly not killed following that operation.
   8888                     //
   8889                     // We execute this kill when these conditions hold:
   8890                     //    1. it's not a system-uid process,
   8891                     //    2. the app did not request its own restore (mTargetPackage == null), and either
   8892                     //    3a. the app is a full-data target (TYPE_FULL_STREAM) or
   8893                     //     b. the app does not state android:killAfterRestore="false" in its manifest
   8894                     final int appFlags = mCurrentPackage.applicationInfo.flags;
   8895                     final boolean killAfterRestore =
   8896                             (mCurrentPackage.applicationInfo.uid >= Process.FIRST_APPLICATION_UID)
   8897                             && ((mRestoreDescription.getDataType() == RestoreDescription.TYPE_FULL_STREAM)
   8898                                     || ((appFlags & ApplicationInfo.FLAG_KILL_AFTER_RESTORE) != 0));
   8899 
   8900                     if (mTargetPackage == null && killAfterRestore) {
   8901                         if (DEBUG) Slog.d(TAG, "Restore complete, killing host process of "
   8902                                 + mCurrentPackage.applicationInfo.processName);
   8903                         mActivityManager.killApplicationProcess(
   8904                                 mCurrentPackage.applicationInfo.processName,
   8905                                 mCurrentPackage.applicationInfo.uid);
   8906                     }
   8907                 } catch (RemoteException e) {
   8908                     // can't happen; we run in the same process as the activity manager
   8909                 }
   8910             }
   8911 
   8912             // The caller is responsible for reestablishing the state machine; our
   8913             // responsibility here is to clear the decks for whatever comes next.
   8914             mBackupHandler.removeMessages(MSG_TIMEOUT, this);
   8915             synchronized (mCurrentOpLock) {
   8916                 mCurrentOperations.clear();
   8917             }
   8918         }
   8919 
   8920         @Override
   8921         public void operationComplete(long unusedResult) {
   8922             if (MORE_DEBUG) {
   8923                 Slog.i(TAG, "operationComplete() during restore: target="
   8924                         + mCurrentPackage.packageName
   8925                         + " state=" + mState);
   8926             }
   8927 
   8928             final UnifiedRestoreState nextState;
   8929             switch (mState) {
   8930                 case INITIAL:
   8931                     // We've just (manually) restored the PMBA.  It doesn't need the
   8932                     // additional restore-finished callback so we bypass that and go
   8933                     // directly to running the queue.
   8934                     nextState = UnifiedRestoreState.RUNNING_QUEUE;
   8935                     break;
   8936 
   8937                 case RESTORE_KEYVALUE:
   8938                 case RESTORE_FULL: {
   8939                     // Okay, we've just heard back from the agent that it's done with
   8940                     // the restore itself.  We now have to send the same agent its
   8941                     // doRestoreFinished() callback, so roll into that state.
   8942                     nextState = UnifiedRestoreState.RESTORE_FINISHED;
   8943                     break;
   8944                 }
   8945 
   8946                 case RESTORE_FINISHED: {
   8947                     // Okay, we're done with this package.  Tidy up and go on to the next
   8948                     // app in the queue.
   8949                     int size = (int) mBackupDataName.length();
   8950                     EventLog.writeEvent(EventLogTags.RESTORE_PACKAGE,
   8951                             mCurrentPackage.packageName, size);
   8952 
   8953                     // Just go back to running the restore queue
   8954                     keyValueAgentCleanup();
   8955 
   8956                     // If there was widget state associated with this app, get the OS to
   8957                     // incorporate it into current bookeeping and then pass that along to
   8958                     // the app as part of the restore-time work.
   8959                     if (mWidgetData != null) {
   8960                         restoreWidgetData(mCurrentPackage.packageName, mWidgetData);
   8961                     }
   8962 
   8963                     nextState = UnifiedRestoreState.RUNNING_QUEUE;
   8964                     break;
   8965                 }
   8966 
   8967                 default: {
   8968                     // Some kind of horrible semantic error; we're in an unexpected state.
   8969                     // Back off hard and wind up.
   8970                     Slog.e(TAG, "Unexpected restore callback into state " + mState);
   8971                     keyValueAgentErrorCleanup();
   8972                     nextState = UnifiedRestoreState.FINAL;
   8973                     break;
   8974                 }
   8975             }
   8976 
   8977             executeNextState(nextState);
   8978         }
   8979 
   8980         // A call to agent.doRestore() or agent.doRestoreFinished() has timed out
   8981         @Override
   8982         public void handleTimeout() {
   8983             Slog.e(TAG, "Timeout restoring application " + mCurrentPackage.packageName);
   8984             EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
   8985                     mCurrentPackage.packageName, "restore timeout");
   8986             // Handle like an agent that threw on invocation: wipe it and go on to the next
   8987             keyValueAgentErrorCleanup();
   8988             executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
   8989         }
   8990 
   8991         void executeNextState(UnifiedRestoreState nextState) {
   8992             if (MORE_DEBUG) Slog.i(TAG, " => executing next step on "
   8993                     + this + " nextState=" + nextState);
   8994             mState = nextState;
   8995             Message msg = mBackupHandler.obtainMessage(MSG_BACKUP_RESTORE_STEP, this);
   8996             mBackupHandler.sendMessage(msg);
   8997         }
   8998 
   8999         // restore observer support
   9000         void sendStartRestore(int numPackages) {
   9001             if (mObserver != null) {
   9002                 try {
   9003                     mObserver.restoreStarting(numPackages);
   9004                 } catch (RemoteException e) {
   9005                     Slog.w(TAG, "Restore observer went away: startRestore");
   9006                     mObserver = null;
   9007                 }
   9008             }
   9009         }
   9010 
   9011         void sendOnRestorePackage(String name) {
   9012             if (mObserver != null) {
   9013                 if (mObserver != null) {
   9014                     try {
   9015                         mObserver.onUpdate(mCount, name);
   9016                     } catch (RemoteException e) {
   9017                         Slog.d(TAG, "Restore observer died in onUpdate");
   9018                         mObserver = null;
   9019                     }
   9020                 }
   9021             }
   9022         }
   9023 
   9024         void sendEndRestore() {
   9025             if (mObserver != null) {
   9026                 try {
   9027                     mObserver.restoreFinished(mStatus);
   9028                 } catch (RemoteException e) {
   9029                     Slog.w(TAG, "Restore observer went away: endRestore");
   9030                     mObserver = null;
   9031                 }
   9032             }
   9033         }
   9034     }
   9035 
   9036     class PerformClearTask implements Runnable {
   9037         IBackupTransport mTransport;
   9038         PackageInfo mPackage;
   9039 
   9040         PerformClearTask(IBackupTransport transport, PackageInfo packageInfo) {
   9041             mTransport = transport;
   9042             mPackage = packageInfo;
   9043         }
   9044 
   9045         public void run() {
   9046             try {
   9047                 // Clear the on-device backup state to ensure a full backup next time
   9048                 File stateDir = new File(mBaseStateDir, mTransport.transportDirName());
   9049                 File stateFile = new File(stateDir, mPackage.packageName);
   9050                 stateFile.delete();
   9051 
   9052                 // Tell the transport to remove all the persistent storage for the app
   9053                 // TODO - need to handle failures
   9054                 mTransport.clearBackupData(mPackage);
   9055             } catch (Exception e) {
   9056                 Slog.e(TAG, "Transport threw clearing data for " + mPackage + ": " + e.getMessage());
   9057             } finally {
   9058                 try {
   9059                     // TODO - need to handle failures
   9060                     mTransport.finishBackup();
   9061                 } catch (Exception e) {
   9062                     // Nothing we can do here, alas
   9063                     Slog.e(TAG, "Unable to mark clear operation finished: " + e.getMessage());
   9064                 }
   9065 
   9066                 // Last but not least, release the cpu
   9067                 mWakelock.release();
   9068             }
   9069         }
   9070     }
   9071 
   9072     class PerformInitializeTask implements Runnable {
   9073         HashSet<String> mQueue;
   9074 
   9075         PerformInitializeTask(HashSet<String> transportNames) {
   9076             mQueue = transportNames;
   9077         }
   9078 
   9079         public void run() {
   9080             try {
   9081                 for (String transportName : mQueue) {
   9082                     IBackupTransport transport = getTransport(transportName);
   9083                     if (transport == null) {
   9084                         Slog.e(TAG, "Requested init for " + transportName + " but not found");
   9085                         continue;
   9086                     }
   9087 
   9088                     Slog.i(TAG, "Initializing (wiping) backup transport storage: " + transportName);
   9089                     EventLog.writeEvent(EventLogTags.BACKUP_START, transport.transportDirName());
   9090                     long startRealtime = SystemClock.elapsedRealtime();
   9091                     int status = transport.initializeDevice();
   9092 
   9093                     if (status == BackupTransport.TRANSPORT_OK) {
   9094                         status = transport.finishBackup();
   9095                     }
   9096 
   9097                     // Okay, the wipe really happened.  Clean up our local bookkeeping.
   9098                     if (status == BackupTransport.TRANSPORT_OK) {
   9099                         Slog.i(TAG, "Device init successful");
   9100                         int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
   9101                         EventLog.writeEvent(EventLogTags.BACKUP_INITIALIZE);
   9102                         resetBackupState(new File(mBaseStateDir, transport.transportDirName()));
   9103                         EventLog.writeEvent(EventLogTags.BACKUP_SUCCESS, 0, millis);
   9104                         synchronized (mQueueLock) {
   9105                             recordInitPendingLocked(false, transportName);
   9106                         }
   9107                     } else {
   9108                         // If this didn't work, requeue this one and try again
   9109                         // after a suitable interval
   9110                         Slog.e(TAG, "Transport error in initializeDevice()");
   9111                         EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, "(initialize)");
   9112                         synchronized (mQueueLock) {
   9113                             recordInitPendingLocked(true, transportName);
   9114                         }
   9115                         // do this via another alarm to make sure of the wakelock states
   9116                         long delay = transport.requestBackupTime();
   9117                         Slog.w(TAG, "Init failed on " + transportName + " resched in " + delay);
   9118                         mAlarmManager.set(AlarmManager.RTC_WAKEUP,
   9119                                 System.currentTimeMillis() + delay, mRunInitIntent);
   9120                     }
   9121                 }
   9122             } catch (Exception e) {
   9123                 Slog.e(TAG, "Unexpected error performing init", e);
   9124             } finally {
   9125                 // Done; release the wakelock
   9126                 mWakelock.release();
   9127             }
   9128         }
   9129     }
   9130 
   9131     private void dataChangedImpl(String packageName) {
   9132         HashSet<String> targets = dataChangedTargets(packageName);
   9133         dataChangedImpl(packageName, targets);
   9134     }
   9135 
   9136     private void dataChangedImpl(String packageName, HashSet<String> targets) {
   9137         // Record that we need a backup pass for the caller.  Since multiple callers
   9138         // may share a uid, we need to note all candidates within that uid and schedule
   9139         // a backup pass for each of them.
   9140         if (targets == null) {
   9141             Slog.w(TAG, "dataChanged but no participant pkg='" + packageName + "'"
   9142                    + " uid=" + Binder.getCallingUid());
   9143             return;
   9144         }
   9145 
   9146         synchronized (mQueueLock) {
   9147             // Note that this client has made data changes that need to be backed up
   9148             if (targets.contains(packageName)) {
   9149                 // Add the caller to the set of pending backups.  If there is
   9150                 // one already there, then overwrite it, but no harm done.
   9151                 BackupRequest req = new BackupRequest(packageName);
   9152                 if (mPendingBackups.put(packageName, req) == null) {
   9153                     if (MORE_DEBUG) Slog.d(TAG, "Now staging backup of " + packageName);
   9154 
   9155                     // Journal this request in case of crash.  The put()
   9156                     // operation returned null when this package was not already
   9157                     // in the set; we want to avoid touching the disk redundantly.
   9158                     writeToJournalLocked(packageName);
   9159                 }
   9160             }
   9161         }
   9162 
   9163         // ...and schedule a backup pass if necessary
   9164         KeyValueBackupJob.schedule(mContext);
   9165     }
   9166 
   9167     // Note: packageName is currently unused, but may be in the future
   9168     private HashSet<String> dataChangedTargets(String packageName) {
   9169         // If the caller does not hold the BACKUP permission, it can only request a
   9170         // backup of its own data.
   9171         if ((mContext.checkPermission(android.Manifest.permission.BACKUP, Binder.getCallingPid(),
   9172                 Binder.getCallingUid())) == PackageManager.PERMISSION_DENIED) {
   9173             synchronized (mBackupParticipants) {
   9174                 return mBackupParticipants.get(Binder.getCallingUid());
   9175             }
   9176         }
   9177 
   9178         // a caller with full permission can ask to back up any participating app
   9179         HashSet<String> targets = new HashSet<String>();
   9180         if (PACKAGE_MANAGER_SENTINEL.equals(packageName)) {
   9181             targets.add(PACKAGE_MANAGER_SENTINEL);
   9182         } else {
   9183             synchronized (mBackupParticipants) {
   9184                 int N = mBackupParticipants.size();
   9185                 for (int i = 0; i < N; i++) {
   9186                     HashSet<String> s = mBackupParticipants.valueAt(i);
   9187                     if (s != null) {
   9188                         targets.addAll(s);
   9189                     }
   9190                 }
   9191             }
   9192         }
   9193         return targets;
   9194     }
   9195 
   9196     private void writeToJournalLocked(String str) {
   9197         RandomAccessFile out = null;
   9198         try {
   9199             if (mJournal == null) mJournal = File.createTempFile("journal", null, mJournalDir);
   9200             out = new RandomAccessFile(mJournal, "rws");
   9201             out.seek(out.length());
   9202             out.writeUTF(str);
   9203         } catch (IOException e) {
   9204             Slog.e(TAG, "Can't write " + str + " to backup journal", e);
   9205             mJournal = null;
   9206         } finally {
   9207             try { if (out != null) out.close(); } catch (IOException e) {}
   9208         }
   9209     }
   9210 
   9211     // ----- IBackupManager binder interface -----
   9212 
   9213     public void dataChanged(final String packageName) {
   9214         final int callingUserHandle = UserHandle.getCallingUserId();
   9215         if (callingUserHandle != UserHandle.USER_SYSTEM) {
   9216             // TODO: http://b/22388012
   9217             // App is running under a non-owner user profile.  For now, we do not back
   9218             // up data from secondary user profiles.
   9219             // TODO: backups for all user profiles although don't add backup for profiles
   9220             // without adding admin control in DevicePolicyManager.
   9221             if (MORE_DEBUG) {
   9222                 Slog.v(TAG, "dataChanged(" + packageName + ") ignored because it's user "
   9223                         + callingUserHandle);
   9224             }
   9225             return;
   9226         }
   9227 
   9228         final HashSet<String> targets = dataChangedTargets(packageName);
   9229         if (targets == null) {
   9230             Slog.w(TAG, "dataChanged but no participant pkg='" + packageName + "'"
   9231                    + " uid=" + Binder.getCallingUid());
   9232             return;
   9233         }
   9234 
   9235         mBackupHandler.post(new Runnable() {
   9236                 public void run() {
   9237                     dataChangedImpl(packageName, targets);
   9238                 }
   9239             });
   9240     }
   9241 
   9242     // Clear the given package's backup data from the current transport
   9243     public void clearBackupData(String transportName, String packageName) {
   9244         if (DEBUG) Slog.v(TAG, "clearBackupData() of " + packageName + " on " + transportName);
   9245         PackageInfo info;
   9246         try {
   9247             info = mPackageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
   9248         } catch (NameNotFoundException e) {
   9249             Slog.d(TAG, "No such package '" + packageName + "' - not clearing backup data");
   9250             return;
   9251         }
   9252 
   9253         // If the caller does not hold the BACKUP permission, it can only request a
   9254         // wipe of its own backed-up data.
   9255         HashSet<String> apps;
   9256         if ((mContext.checkPermission(android.Manifest.permission.BACKUP, Binder.getCallingPid(),
   9257                 Binder.getCallingUid())) == PackageManager.PERMISSION_DENIED) {
   9258             apps = mBackupParticipants.get(Binder.getCallingUid());
   9259         } else {
   9260             // a caller with full permission can ask to back up any participating app
   9261             // !!! TODO: allow data-clear of ANY app?
   9262             if (MORE_DEBUG) Slog.v(TAG, "Privileged caller, allowing clear of other apps");
   9263             apps = new HashSet<String>();
   9264             int N = mBackupParticipants.size();
   9265             for (int i = 0; i < N; i++) {
   9266                 HashSet<String> s = mBackupParticipants.valueAt(i);
   9267                 if (s != null) {
   9268                     apps.addAll(s);
   9269                 }
   9270             }
   9271         }
   9272 
   9273         // Is the given app an available participant?
   9274         if (apps.contains(packageName)) {
   9275             // found it; fire off the clear request
   9276             if (MORE_DEBUG) Slog.v(TAG, "Found the app - running clear process");
   9277             mBackupHandler.removeMessages(MSG_RETRY_CLEAR);
   9278             synchronized (mQueueLock) {
   9279                 final IBackupTransport transport = getTransport(transportName);
   9280                 if (transport == null) {
   9281                     // transport is currently unavailable -- make sure to retry
   9282                     Message msg = mBackupHandler.obtainMessage(MSG_RETRY_CLEAR,
   9283                             new ClearRetryParams(transportName, packageName));
   9284                     mBackupHandler.sendMessageDelayed(msg, TRANSPORT_RETRY_INTERVAL);
   9285                     return;
   9286                 }
   9287                 long oldId = Binder.clearCallingIdentity();
   9288                 mWakelock.acquire();
   9289                 Message msg = mBackupHandler.obtainMessage(MSG_RUN_CLEAR,
   9290                         new ClearParams(transport, info));
   9291                 mBackupHandler.sendMessage(msg);
   9292                 Binder.restoreCallingIdentity(oldId);
   9293             }
   9294         }
   9295     }
   9296 
   9297     // Run a backup pass immediately for any applications that have declared
   9298     // that they have pending updates.
   9299     public void backupNow() {
   9300         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "backupNow");
   9301 
   9302         if (mPowerManager.isPowerSaveMode()) {
   9303             if (DEBUG) Slog.v(TAG, "Not running backup while in battery save mode");
   9304             KeyValueBackupJob.schedule(mContext);   // try again in several hours
   9305         } else {
   9306             if (DEBUG) Slog.v(TAG, "Scheduling immediate backup pass");
   9307             synchronized (mQueueLock) {
   9308                 // Fire the intent that kicks off the whole shebang...
   9309                 try {
   9310                     mRunBackupIntent.send();
   9311                 } catch (PendingIntent.CanceledException e) {
   9312                     // should never happen
   9313                     Slog.e(TAG, "run-backup intent cancelled!");
   9314                 }
   9315 
   9316                 // ...and cancel any pending scheduled job, because we've just superseded it
   9317                 KeyValueBackupJob.cancel(mContext);
   9318             }
   9319         }
   9320     }
   9321 
   9322     boolean deviceIsProvisioned() {
   9323         final ContentResolver resolver = mContext.getContentResolver();
   9324         return (Settings.Global.getInt(resolver, Settings.Global.DEVICE_PROVISIONED, 0) != 0);
   9325     }
   9326 
   9327     // Run a *full* backup pass for the given packages, writing the resulting data stream
   9328     // to the supplied file descriptor.  This method is synchronous and does not return
   9329     // to the caller until the backup has been completed.
   9330     //
   9331     // This is the variant used by 'adb backup'; it requires on-screen confirmation
   9332     // by the user because it can be used to offload data over untrusted USB.
   9333     public void fullBackup(ParcelFileDescriptor fd, boolean includeApks,
   9334             boolean includeObbs, boolean includeShared, boolean doWidgets,
   9335             boolean doAllApps, boolean includeSystem, boolean compress, String[] pkgList) {
   9336         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "fullBackup");
   9337 
   9338         final int callingUserHandle = UserHandle.getCallingUserId();
   9339         // TODO: http://b/22388012
   9340         if (callingUserHandle != UserHandle.USER_SYSTEM) {
   9341             throw new IllegalStateException("Backup supported only for the device owner");
   9342         }
   9343 
   9344         // Validate
   9345         if (!doAllApps) {
   9346             if (!includeShared) {
   9347                 // If we're backing up shared data (sdcard or equivalent), then we can run
   9348                 // without any supplied app names.  Otherwise, we'd be doing no work, so
   9349                 // report the error.
   9350                 if (pkgList == null || pkgList.length == 0) {
   9351                     throw new IllegalArgumentException(
   9352                             "Backup requested but neither shared nor any apps named");
   9353                 }
   9354             }
   9355         }
   9356 
   9357         long oldId = Binder.clearCallingIdentity();
   9358         try {
   9359             // Doesn't make sense to do a full backup prior to setup
   9360             if (!deviceIsProvisioned()) {
   9361                 Slog.i(TAG, "Full backup not supported before setup");
   9362                 return;
   9363             }
   9364 
   9365             if (DEBUG) Slog.v(TAG, "Requesting full backup: apks=" + includeApks
   9366                     + " obb=" + includeObbs + " shared=" + includeShared + " all=" + doAllApps
   9367                     + " system=" + includeSystem + " pkgs=" + pkgList);
   9368             Slog.i(TAG, "Beginning full backup...");
   9369 
   9370             FullBackupParams params = new FullBackupParams(fd, includeApks, includeObbs,
   9371                     includeShared, doWidgets, doAllApps, includeSystem, compress, pkgList);
   9372             final int token = generateToken();
   9373             synchronized (mFullConfirmations) {
   9374                 mFullConfirmations.put(token, params);
   9375             }
   9376 
   9377             // start up the confirmation UI
   9378             if (DEBUG) Slog.d(TAG, "Starting backup confirmation UI, token=" + token);
   9379             if (!startConfirmationUi(token, FullBackup.FULL_BACKUP_INTENT_ACTION)) {
   9380                 Slog.e(TAG, "Unable to launch full backup confirmation");
   9381                 mFullConfirmations.delete(token);
   9382                 return;
   9383             }
   9384 
   9385             // make sure the screen is lit for the user interaction
   9386             mPowerManager.userActivity(SystemClock.uptimeMillis(),
   9387                     PowerManager.USER_ACTIVITY_EVENT_OTHER,
   9388                     0);
   9389 
   9390             // start the confirmation countdown
   9391             startConfirmationTimeout(token, params);
   9392 
   9393             // wait for the backup to be performed
   9394             if (DEBUG) Slog.d(TAG, "Waiting for full backup completion...");
   9395             waitForCompletion(params);
   9396         } finally {
   9397             try {
   9398                 fd.close();
   9399             } catch (IOException e) {
   9400                 // just eat it
   9401             }
   9402             Binder.restoreCallingIdentity(oldId);
   9403             Slog.d(TAG, "Full backup processing complete.");
   9404         }
   9405     }
   9406 
   9407     public void fullTransportBackup(String[] pkgNames) {
   9408         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP,
   9409                 "fullTransportBackup");
   9410 
   9411         final int callingUserHandle = UserHandle.getCallingUserId();
   9412         // TODO: http://b/22388012
   9413         if (callingUserHandle != UserHandle.USER_SYSTEM) {
   9414             throw new IllegalStateException("Restore supported only for the device owner");
   9415         }
   9416 
   9417         if (!fullBackupAllowable(getTransport(mCurrentTransport))) {
   9418             Slog.i(TAG, "Full backup not currently possible -- key/value backup not yet run?");
   9419         } else {
   9420             if (DEBUG) {
   9421                 Slog.d(TAG, "fullTransportBackup()");
   9422             }
   9423 
   9424             final long oldId = Binder.clearCallingIdentity();
   9425             try {
   9426                 CountDownLatch latch = new CountDownLatch(1);
   9427                 PerformFullTransportBackupTask task = new PerformFullTransportBackupTask(null,
   9428                         pkgNames, false, null, latch, null, false /* userInitiated */);
   9429                 // Acquiring wakelock for PerformFullTransportBackupTask before its start.
   9430                 mWakelock.acquire();
   9431                 (new Thread(task, "full-transport-master")).start();
   9432                 do {
   9433                     try {
   9434                         latch.await();
   9435                         break;
   9436                     } catch (InterruptedException e) {
   9437                         // Just go back to waiting for the latch to indicate completion
   9438                     }
   9439                 } while (true);
   9440 
   9441                 // We just ran a backup on these packages, so kick them to the end of the queue
   9442                 final long now = System.currentTimeMillis();
   9443                 for (String pkg : pkgNames) {
   9444                     enqueueFullBackup(pkg, now);
   9445                 }
   9446             } finally {
   9447                 Binder.restoreCallingIdentity(oldId);
   9448             }
   9449         }
   9450 
   9451         if (DEBUG) {
   9452             Slog.d(TAG, "Done with full transport backup.");
   9453         }
   9454     }
   9455 
   9456     public void fullRestore(ParcelFileDescriptor fd) {
   9457         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "fullRestore");
   9458 
   9459         final int callingUserHandle = UserHandle.getCallingUserId();
   9460         // TODO: http://b/22388012
   9461         if (callingUserHandle != UserHandle.USER_SYSTEM) {
   9462             throw new IllegalStateException("Restore supported only for the device owner");
   9463         }
   9464 
   9465         long oldId = Binder.clearCallingIdentity();
   9466 
   9467         try {
   9468             // Check whether the device has been provisioned -- we don't handle
   9469             // full restores prior to completing the setup process.
   9470             if (!deviceIsProvisioned()) {
   9471                 Slog.i(TAG, "Full restore not permitted before setup");
   9472                 return;
   9473             }
   9474 
   9475             Slog.i(TAG, "Beginning full restore...");
   9476 
   9477             FullRestoreParams params = new FullRestoreParams(fd);
   9478             final int token = generateToken();
   9479             synchronized (mFullConfirmations) {
   9480                 mFullConfirmations.put(token, params);
   9481             }
   9482 
   9483             // start up the confirmation UI
   9484             if (DEBUG) Slog.d(TAG, "Starting restore confirmation UI, token=" + token);
   9485             if (!startConfirmationUi(token, FullBackup.FULL_RESTORE_INTENT_ACTION)) {
   9486                 Slog.e(TAG, "Unable to launch full restore confirmation");
   9487                 mFullConfirmations.delete(token);
   9488                 return;
   9489             }
   9490 
   9491             // make sure the screen is lit for the user interaction
   9492             mPowerManager.userActivity(SystemClock.uptimeMillis(),
   9493                     PowerManager.USER_ACTIVITY_EVENT_OTHER,
   9494                     0);
   9495 
   9496             // start the confirmation countdown
   9497             startConfirmationTimeout(token, params);
   9498 
   9499             // wait for the restore to be performed
   9500             if (DEBUG) Slog.d(TAG, "Waiting for full restore completion...");
   9501             waitForCompletion(params);
   9502         } finally {
   9503             try {
   9504                 fd.close();
   9505             } catch (IOException e) {
   9506                 Slog.w(TAG, "Error trying to close fd after full restore: " + e);
   9507             }
   9508             Binder.restoreCallingIdentity(oldId);
   9509             Slog.i(TAG, "Full restore processing complete.");
   9510         }
   9511     }
   9512 
   9513     boolean startConfirmationUi(int token, String action) {
   9514         try {
   9515             Intent confIntent = new Intent(action);
   9516             confIntent.setClassName("com.android.backupconfirm",
   9517                     "com.android.backupconfirm.BackupRestoreConfirmation");
   9518             confIntent.putExtra(FullBackup.CONF_TOKEN_INTENT_EXTRA, token);
   9519             confIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
   9520             mContext.startActivityAsUser(confIntent, UserHandle.SYSTEM);
   9521         } catch (ActivityNotFoundException e) {
   9522             return false;
   9523         }
   9524         return true;
   9525     }
   9526 
   9527     void startConfirmationTimeout(int token, FullParams params) {
   9528         if (MORE_DEBUG) Slog.d(TAG, "Posting conf timeout msg after "
   9529                 + TIMEOUT_FULL_CONFIRMATION + " millis");
   9530         Message msg = mBackupHandler.obtainMessage(MSG_FULL_CONFIRMATION_TIMEOUT,
   9531                 token, 0, params);
   9532         mBackupHandler.sendMessageDelayed(msg, TIMEOUT_FULL_CONFIRMATION);
   9533     }
   9534 
   9535     void waitForCompletion(FullParams params) {
   9536         synchronized (params.latch) {
   9537             while (params.latch.get() == false) {
   9538                 try {
   9539                     params.latch.wait();
   9540                 } catch (InterruptedException e) { /* never interrupted */ }
   9541             }
   9542         }
   9543     }
   9544 
   9545     void signalFullBackupRestoreCompletion(FullParams params) {
   9546         synchronized (params.latch) {
   9547             params.latch.set(true);
   9548             params.latch.notifyAll();
   9549         }
   9550     }
   9551 
   9552     // Confirm that the previously-requested full backup/restore operation can proceed.  This
   9553     // is used to require a user-facing disclosure about the operation.
   9554     public void acknowledgeFullBackupOrRestore(int token, boolean allow,
   9555             String curPassword, String encPpassword, IFullBackupRestoreObserver observer) {
   9556         if (DEBUG) Slog.d(TAG, "acknowledgeFullBackupOrRestore : token=" + token
   9557                 + " allow=" + allow);
   9558 
   9559         // TODO: possibly require not just this signature-only permission, but even
   9560         // require that the specific designated confirmation-UI app uid is the caller?
   9561         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "acknowledgeFullBackupOrRestore");
   9562 
   9563         long oldId = Binder.clearCallingIdentity();
   9564         try {
   9565 
   9566             FullParams params;
   9567             synchronized (mFullConfirmations) {
   9568                 params = mFullConfirmations.get(token);
   9569                 if (params != null) {
   9570                     mBackupHandler.removeMessages(MSG_FULL_CONFIRMATION_TIMEOUT, params);
   9571                     mFullConfirmations.delete(token);
   9572 
   9573                     if (allow) {
   9574                         final int verb = params instanceof FullBackupParams
   9575                                 ? MSG_RUN_ADB_BACKUP
   9576                                 : MSG_RUN_ADB_RESTORE;
   9577 
   9578                         params.observer = observer;
   9579                         params.curPassword = curPassword;
   9580 
   9581                         params.encryptPassword = encPpassword;
   9582 
   9583                         if (MORE_DEBUG) Slog.d(TAG, "Sending conf message with verb " + verb);
   9584                         mWakelock.acquire();
   9585                         Message msg = mBackupHandler.obtainMessage(verb, params);
   9586                         mBackupHandler.sendMessage(msg);
   9587                     } else {
   9588                         Slog.w(TAG, "User rejected full backup/restore operation");
   9589                         // indicate completion without having actually transferred any data
   9590                         signalFullBackupRestoreCompletion(params);
   9591                     }
   9592                 } else {
   9593                     Slog.w(TAG, "Attempted to ack full backup/restore with invalid token");
   9594                 }
   9595             }
   9596         } finally {
   9597             Binder.restoreCallingIdentity(oldId);
   9598         }
   9599     }
   9600 
   9601     private static boolean backupSettingMigrated(int userId) {
   9602         File base = new File(Environment.getDataDirectory(), "backup");
   9603         File enableFile = new File(base, BACKUP_ENABLE_FILE);
   9604         return enableFile.exists();
   9605     }
   9606 
   9607     private static boolean readBackupEnableState(int userId) {
   9608         File base = new File(Environment.getDataDirectory(), "backup");
   9609         File enableFile = new File(base, BACKUP_ENABLE_FILE);
   9610         if (enableFile.exists()) {
   9611             try (FileInputStream fin = new FileInputStream(enableFile)) {
   9612                 int state = fin.read();
   9613                 return state != 0;
   9614             } catch (IOException e) {
   9615                 // can't read the file; fall through to assume disabled
   9616                 Slog.e(TAG, "Cannot read enable state; assuming disabled");
   9617             }
   9618         } else {
   9619             if (DEBUG) {
   9620                 Slog.i(TAG, "isBackupEnabled() => false due to absent settings file");
   9621             }
   9622         }
   9623         return false;
   9624     }
   9625 
   9626     private static void writeBackupEnableState(boolean enable, int userId) {
   9627         File base = new File(Environment.getDataDirectory(), "backup");
   9628         File enableFile = new File(base, BACKUP_ENABLE_FILE);
   9629         File stage = new File(base, BACKUP_ENABLE_FILE + "-stage");
   9630         FileOutputStream fout = null;
   9631         try {
   9632             fout = new FileOutputStream(stage);
   9633             fout.write(enable ? 1 : 0);
   9634             fout.close();
   9635             stage.renameTo(enableFile);
   9636             // will be synced immediately by the try-with-resources call to close()
   9637         } catch (IOException|RuntimeException e) {
   9638             // Whoops; looks like we're doomed.  Roll everything out, disabled,
   9639             // including the legacy state.
   9640             Slog.e(TAG, "Unable to record backup enable state; reverting to disabled: "
   9641                     + e.getMessage());
   9642 
   9643             final ContentResolver r = sInstance.mContext.getContentResolver();
   9644             Settings.Secure.putStringForUser(r,
   9645                     Settings.Secure.BACKUP_ENABLED, null, userId);
   9646             enableFile.delete();
   9647             stage.delete();
   9648         } finally {
   9649             IoUtils.closeQuietly(fout);
   9650         }
   9651     }
   9652 
   9653     // Enable/disable backups
   9654     public void setBackupEnabled(boolean enable) {
   9655         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   9656                 "setBackupEnabled");
   9657 
   9658         Slog.i(TAG, "Backup enabled => " + enable);
   9659 
   9660         long oldId = Binder.clearCallingIdentity();
   9661         try {
   9662             boolean wasEnabled = mEnabled;
   9663             synchronized (this) {
   9664                 writeBackupEnableState(enable, UserHandle.USER_SYSTEM);
   9665                 mEnabled = enable;
   9666             }
   9667 
   9668             synchronized (mQueueLock) {
   9669                 if (enable && !wasEnabled && mProvisioned) {
   9670                     // if we've just been enabled, start scheduling backup passes
   9671                     KeyValueBackupJob.schedule(mContext);
   9672                     scheduleNextFullBackupJob(0);
   9673                 } else if (!enable) {
   9674                     // No longer enabled, so stop running backups
   9675                     if (MORE_DEBUG) Slog.i(TAG, "Opting out of backup");
   9676 
   9677                     KeyValueBackupJob.cancel(mContext);
   9678 
   9679                     // This also constitutes an opt-out, so we wipe any data for
   9680                     // this device from the backend.  We start that process with
   9681                     // an alarm in order to guarantee wakelock states.
   9682                     if (wasEnabled && mProvisioned) {
   9683                         // NOTE: we currently flush every registered transport, not just
   9684                         // the currently-active one.
   9685                         HashSet<String> allTransports;
   9686                         synchronized (mTransports) {
   9687                             allTransports = new HashSet<String>(mTransports.keySet());
   9688                         }
   9689                         // build the set of transports for which we are posting an init
   9690                         for (String transport : allTransports) {
   9691                             recordInitPendingLocked(true, transport);
   9692                         }
   9693                         mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
   9694                                 mRunInitIntent);
   9695                     }
   9696                 }
   9697             }
   9698         } finally {
   9699             Binder.restoreCallingIdentity(oldId);
   9700         }
   9701     }
   9702 
   9703     // Enable/disable automatic restore of app data at install time
   9704     public void setAutoRestore(boolean doAutoRestore) {
   9705         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   9706                 "setAutoRestore");
   9707 
   9708         Slog.i(TAG, "Auto restore => " + doAutoRestore);
   9709 
   9710         final long oldId = Binder.clearCallingIdentity();
   9711         try {
   9712             synchronized (this) {
   9713                 Settings.Secure.putInt(mContext.getContentResolver(),
   9714                         Settings.Secure.BACKUP_AUTO_RESTORE, doAutoRestore ? 1 : 0);
   9715                 mAutoRestore = doAutoRestore;
   9716             }
   9717         } finally {
   9718             Binder.restoreCallingIdentity(oldId);
   9719         }
   9720     }
   9721 
   9722     // Mark the backup service as having been provisioned
   9723     public void setBackupProvisioned(boolean available) {
   9724         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   9725                 "setBackupProvisioned");
   9726         /*
   9727          * This is now a no-op; provisioning is simply the device's own setup state.
   9728          */
   9729     }
   9730 
   9731     // Report whether the backup mechanism is currently enabled
   9732     public boolean isBackupEnabled() {
   9733         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "isBackupEnabled");
   9734         return mEnabled;    // no need to synchronize just to read it
   9735     }
   9736 
   9737     // Report the name of the currently active transport
   9738     public String getCurrentTransport() {
   9739         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   9740                 "getCurrentTransport");
   9741         if (MORE_DEBUG) Slog.v(TAG, "... getCurrentTransport() returning " + mCurrentTransport);
   9742         return mCurrentTransport;
   9743     }
   9744 
   9745     // Report all known, available backup transports
   9746     public String[] listAllTransports() {
   9747         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "listAllTransports");
   9748 
   9749         String[] list = null;
   9750         ArrayList<String> known = new ArrayList<String>();
   9751         for (Map.Entry<String, IBackupTransport> entry : mTransports.entrySet()) {
   9752             if (entry.getValue() != null) {
   9753                 known.add(entry.getKey());
   9754             }
   9755         }
   9756 
   9757         if (known.size() > 0) {
   9758             list = new String[known.size()];
   9759             known.toArray(list);
   9760         }
   9761         return list;
   9762     }
   9763 
   9764     public String[] getTransportWhitelist() {
   9765         // No permission check, intentionally.
   9766         String[] whitelist = new String[mTransportWhitelist.size()];
   9767         for (int i = mTransportWhitelist.size() - 1; i >= 0; i--) {
   9768             whitelist[i] = mTransportWhitelist.valueAt(i).flattenToShortString();
   9769         }
   9770         return whitelist;
   9771     }
   9772 
   9773     // Select which transport to use for the next backup operation.
   9774     public String selectBackupTransport(String transport) {
   9775         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   9776                 "selectBackupTransport");
   9777 
   9778         synchronized (mTransports) {
   9779             final long oldId = Binder.clearCallingIdentity();
   9780             try {
   9781                 String prevTransport = mCurrentTransport;
   9782                 mCurrentTransport = transport;
   9783                 Settings.Secure.putString(mContext.getContentResolver(),
   9784                         Settings.Secure.BACKUP_TRANSPORT, transport);
   9785                 Slog.v(TAG, "selectBackupTransport() set " + mCurrentTransport
   9786                         + " returning " + prevTransport);
   9787                 return prevTransport;
   9788             } finally {
   9789                 Binder.restoreCallingIdentity(oldId);
   9790             }
   9791         }
   9792     }
   9793 
   9794     // Supply the configuration Intent for the given transport.  If the name is not one
   9795     // of the available transports, or if the transport does not supply any configuration
   9796     // UI, the method returns null.
   9797     public Intent getConfigurationIntent(String transportName) {
   9798         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   9799                 "getConfigurationIntent");
   9800 
   9801         synchronized (mTransports) {
   9802             final IBackupTransport transport = mTransports.get(transportName);
   9803             if (transport != null) {
   9804                 try {
   9805                     final Intent intent = transport.configurationIntent();
   9806                     if (MORE_DEBUG) Slog.d(TAG, "getConfigurationIntent() returning config intent "
   9807                             + intent);
   9808                     return intent;
   9809                 } catch (Exception e) {
   9810                     /* fall through to return null */
   9811                     Slog.e(TAG, "Unable to get configuration intent from transport: " + e.getMessage());
   9812                 }
   9813             }
   9814         }
   9815 
   9816         return null;
   9817     }
   9818 
   9819     // Supply the configuration summary string for the given transport.  If the name is
   9820     // not one of the available transports, or if the transport does not supply any
   9821     // summary / destination string, the method can return null.
   9822     //
   9823     // This string is used VERBATIM as the summary text of the relevant Settings item!
   9824     public String getDestinationString(String transportName) {
   9825         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   9826                 "getDestinationString");
   9827 
   9828         synchronized (mTransports) {
   9829             final IBackupTransport transport = mTransports.get(transportName);
   9830             if (transport != null) {
   9831                 try {
   9832                     final String text = transport.currentDestinationString();
   9833                     if (MORE_DEBUG) Slog.d(TAG, "getDestinationString() returning " + text);
   9834                     return text;
   9835                 } catch (Exception e) {
   9836                     /* fall through to return null */
   9837                     Slog.e(TAG, "Unable to get string from transport: " + e.getMessage());
   9838                 }
   9839             }
   9840         }
   9841 
   9842         return null;
   9843     }
   9844 
   9845     // Supply the manage-data intent for the given transport.
   9846     public Intent getDataManagementIntent(String transportName) {
   9847         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   9848                 "getDataManagementIntent");
   9849 
   9850         synchronized (mTransports) {
   9851             final IBackupTransport transport = mTransports.get(transportName);
   9852             if (transport != null) {
   9853                 try {
   9854                     final Intent intent = transport.dataManagementIntent();
   9855                     if (MORE_DEBUG) Slog.d(TAG, "getDataManagementIntent() returning intent "
   9856                             + intent);
   9857                     return intent;
   9858                 } catch (Exception e) {
   9859                     /* fall through to return null */
   9860                     Slog.e(TAG, "Unable to get management intent from transport: " + e.getMessage());
   9861                 }
   9862             }
   9863         }
   9864 
   9865         return null;
   9866     }
   9867 
   9868     // Supply the menu label for affordances that fire the manage-data intent
   9869     // for the given transport.
   9870     public String getDataManagementLabel(String transportName) {
   9871         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   9872                 "getDataManagementLabel");
   9873 
   9874         synchronized (mTransports) {
   9875             final IBackupTransport transport = mTransports.get(transportName);
   9876             if (transport != null) {
   9877                 try {
   9878                     final String text = transport.dataManagementLabel();
   9879                     if (MORE_DEBUG) Slog.d(TAG, "getDataManagementLabel() returning " + text);
   9880                     return text;
   9881                 } catch (Exception e) {
   9882                     /* fall through to return null */
   9883                     Slog.e(TAG, "Unable to get management label from transport: " + e.getMessage());
   9884                 }
   9885             }
   9886         }
   9887 
   9888         return null;
   9889     }
   9890 
   9891     // Callback: a requested backup agent has been instantiated.  This should only
   9892     // be called from the Activity Manager.
   9893     public void agentConnected(String packageName, IBinder agentBinder) {
   9894         synchronized(mAgentConnectLock) {
   9895             if (Binder.getCallingUid() == Process.SYSTEM_UID) {
   9896                 Slog.d(TAG, "agentConnected pkg=" + packageName + " agent=" + agentBinder);
   9897                 IBackupAgent agent = IBackupAgent.Stub.asInterface(agentBinder);
   9898                 mConnectedAgent = agent;
   9899                 mConnecting = false;
   9900             } else {
   9901                 Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
   9902                         + " claiming agent connected");
   9903             }
   9904             mAgentConnectLock.notifyAll();
   9905         }
   9906     }
   9907 
   9908     // Callback: a backup agent has failed to come up, or has unexpectedly quit.
   9909     // If the agent failed to come up in the first place, the agentBinder argument
   9910     // will be null.  This should only be called from the Activity Manager.
   9911     public void agentDisconnected(String packageName) {
   9912         // TODO: handle backup being interrupted
   9913         synchronized(mAgentConnectLock) {
   9914             if (Binder.getCallingUid() == Process.SYSTEM_UID) {
   9915                 mConnectedAgent = null;
   9916                 mConnecting = false;
   9917             } else {
   9918                 Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
   9919                         + " claiming agent disconnected");
   9920             }
   9921             mAgentConnectLock.notifyAll();
   9922         }
   9923     }
   9924 
   9925     // An application being installed will need a restore pass, then the Package Manager
   9926     // will need to be told when the restore is finished.
   9927     public void restoreAtInstall(String packageName, int token) {
   9928         if (Binder.getCallingUid() != Process.SYSTEM_UID) {
   9929             Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
   9930                     + " attemping install-time restore");
   9931             return;
   9932         }
   9933 
   9934         boolean skip = false;
   9935 
   9936         long restoreSet = getAvailableRestoreToken(packageName);
   9937         if (DEBUG) Slog.v(TAG, "restoreAtInstall pkg=" + packageName
   9938                 + " token=" + Integer.toHexString(token)
   9939                 + " restoreSet=" + Long.toHexString(restoreSet));
   9940         if (restoreSet == 0) {
   9941             if (MORE_DEBUG) Slog.i(TAG, "No restore set");
   9942             skip = true;
   9943         }
   9944 
   9945         // Do we have a transport to fetch data for us?
   9946         IBackupTransport transport = getTransport(mCurrentTransport);
   9947         if (transport == null) {
   9948             if (DEBUG) Slog.w(TAG, "No transport");
   9949             skip = true;
   9950         }
   9951 
   9952         if (!mAutoRestore) {
   9953             if (DEBUG) {
   9954                 Slog.w(TAG, "Non-restorable state: auto=" + mAutoRestore);
   9955             }
   9956             skip = true;
   9957         }
   9958 
   9959         if (!skip) {
   9960             try {
   9961                 // okay, we're going to attempt a restore of this package from this restore set.
   9962                 // The eventual message back into the Package Manager to run the post-install
   9963                 // steps for 'token' will be issued from the restore handling code.
   9964 
   9965                 // This can throw and so *must* happen before the wakelock is acquired
   9966                 String dirName = transport.transportDirName();
   9967 
   9968                 mWakelock.acquire();
   9969                 if (MORE_DEBUG) {
   9970                     Slog.d(TAG, "Restore at install of " + packageName);
   9971                 }
   9972                 Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
   9973                 msg.obj = new RestoreParams(transport, dirName, null,
   9974                         restoreSet, packageName, token);
   9975                 mBackupHandler.sendMessage(msg);
   9976             } catch (Exception e) {
   9977                 // Calling into the transport broke; back off and proceed with the installation.
   9978                 Slog.e(TAG, "Unable to contact transport: " + e.getMessage());
   9979                 skip = true;
   9980             }
   9981         }
   9982 
   9983         if (skip) {
   9984             // Auto-restore disabled or no way to attempt a restore; just tell the Package
   9985             // Manager to proceed with the post-install handling for this package.
   9986             if (DEBUG) Slog.v(TAG, "Finishing install immediately");
   9987             try {
   9988                 mPackageManagerBinder.finishPackageInstall(token, false);
   9989             } catch (RemoteException e) { /* can't happen */ }
   9990         }
   9991     }
   9992 
   9993     // Hand off a restore session
   9994     public IRestoreSession beginRestoreSession(String packageName, String transport) {
   9995         if (DEBUG) Slog.v(TAG, "beginRestoreSession: pkg=" + packageName
   9996                 + " transport=" + transport);
   9997 
   9998         boolean needPermission = true;
   9999         if (transport == null) {
   10000             transport = mCurrentTransport;
   10001 
   10002             if (packageName != null) {
   10003                 PackageInfo app = null;
   10004                 try {
   10005                     app = mPackageManager.getPackageInfo(packageName, 0);
   10006                 } catch (NameNotFoundException nnf) {
   10007                     Slog.w(TAG, "Asked to restore nonexistent pkg " + packageName);
   10008                     throw new IllegalArgumentException("Package " + packageName + " not found");
   10009                 }
   10010 
   10011                 if (app.applicationInfo.uid == Binder.getCallingUid()) {
   10012                     // So: using the current active transport, and the caller has asked
   10013                     // that its own package will be restored.  In this narrow use case
   10014                     // we do not require the caller to hold the permission.
   10015                     needPermission = false;
   10016                 }
   10017             }
   10018         }
   10019 
   10020         if (needPermission) {
   10021             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   10022                     "beginRestoreSession");
   10023         } else {
   10024             if (DEBUG) Slog.d(TAG, "restoring self on current transport; no permission needed");
   10025         }
   10026 
   10027         synchronized(this) {
   10028             if (mActiveRestoreSession != null) {
   10029                 Slog.i(TAG, "Restore session requested but one already active");
   10030                 return null;
   10031             }
   10032             if (mBackupRunning) {
   10033                 Slog.i(TAG, "Restore session requested but currently running backups");
   10034                 return null;
   10035             }
   10036             mActiveRestoreSession = new ActiveRestoreSession(packageName, transport);
   10037             mBackupHandler.sendEmptyMessageDelayed(MSG_RESTORE_TIMEOUT, TIMEOUT_RESTORE_INTERVAL);
   10038         }
   10039         return mActiveRestoreSession;
   10040     }
   10041 
   10042     void clearRestoreSession(ActiveRestoreSession currentSession) {
   10043         synchronized(this) {
   10044             if (currentSession != mActiveRestoreSession) {
   10045                 Slog.e(TAG, "ending non-current restore session");
   10046             } else {
   10047                 if (DEBUG) Slog.v(TAG, "Clearing restore session and halting timeout");
   10048                 mActiveRestoreSession = null;
   10049                 mBackupHandler.removeMessages(MSG_RESTORE_TIMEOUT);
   10050             }
   10051         }
   10052     }
   10053 
   10054     // Note that a currently-active backup agent has notified us that it has
   10055     // completed the given outstanding asynchronous backup/restore operation.
   10056     public void opComplete(int token, long result) {
   10057         if (MORE_DEBUG) {
   10058             Slog.v(TAG, "opComplete: " + Integer.toHexString(token) + " result=" + result);
   10059         }
   10060         Operation op = null;
   10061         synchronized (mCurrentOpLock) {
   10062             op = mCurrentOperations.get(token);
   10063             if (op != null) {
   10064                 if (op.state == OP_TIMEOUT) {
   10065                     // The operation already timed out, and this is a late response.  Tidy up
   10066                     // and ignore it; we've already dealt with the timeout.
   10067                     op = null;
   10068                     mCurrentOperations.delete(token);
   10069                 } else {
   10070                     op.state = OP_ACKNOWLEDGED;
   10071                 }
   10072             }
   10073             mCurrentOpLock.notifyAll();
   10074         }
   10075 
   10076         // The completion callback, if any, is invoked on the handler
   10077         if (op != null && op.callback != null) {
   10078             Pair<BackupRestoreTask, Long> callbackAndResult = Pair.create(op.callback, result);
   10079             Message msg = mBackupHandler.obtainMessage(MSG_OP_COMPLETE, callbackAndResult);
   10080             mBackupHandler.sendMessage(msg);
   10081         }
   10082     }
   10083 
   10084     public boolean isAppEligibleForBackup(String packageName) {
   10085         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   10086                 "isAppEligibleForBackup");
   10087         try {
   10088             PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName,
   10089                     PackageManager.GET_SIGNATURES);
   10090             if (!appIsEligibleForBackup(packageInfo.applicationInfo) ||
   10091                     appIsStopped(packageInfo.applicationInfo)) {
   10092                 return false;
   10093             }
   10094             IBackupTransport transport = getTransport(mCurrentTransport);
   10095             if (transport != null) {
   10096                 try {
   10097                     return transport.isAppEligibleForBackup(packageInfo,
   10098                         appGetsFullBackup(packageInfo));
   10099                 } catch (Exception e) {
   10100                     Slog.e(TAG, "Unable to ask about eligibility: " + e.getMessage());
   10101                 }
   10102             }
   10103             // If transport is not present we couldn't tell that the package is not eligible.
   10104             return true;
   10105         } catch (NameNotFoundException e) {
   10106             return false;
   10107         }
   10108     }
   10109 
   10110     // ----- Restore session -----
   10111 
   10112     class ActiveRestoreSession extends IRestoreSession.Stub {
   10113         private static final String TAG = "RestoreSession";
   10114 
   10115         private String mPackageName;
   10116         private IBackupTransport mRestoreTransport = null;
   10117         RestoreSet[] mRestoreSets = null;
   10118         boolean mEnded = false;
   10119         boolean mTimedOut = false;
   10120 
   10121         ActiveRestoreSession(String packageName, String transport) {
   10122             mPackageName = packageName;
   10123             mRestoreTransport = getTransport(transport);
   10124         }
   10125 
   10126         public void markTimedOut() {
   10127             mTimedOut = true;
   10128         }
   10129 
   10130         // --- Binder interface ---
   10131         public synchronized int getAvailableRestoreSets(IRestoreObserver observer) {
   10132             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   10133                     "getAvailableRestoreSets");
   10134             if (observer == null) {
   10135                 throw new IllegalArgumentException("Observer must not be null");
   10136             }
   10137 
   10138             if (mEnded) {
   10139                 throw new IllegalStateException("Restore session already ended");
   10140             }
   10141 
   10142             if (mTimedOut) {
   10143                 Slog.i(TAG, "Session already timed out");
   10144                 return -1;
   10145             }
   10146 
   10147             long oldId = Binder.clearCallingIdentity();
   10148             try {
   10149                 if (mRestoreTransport == null) {
   10150                     Slog.w(TAG, "Null transport getting restore sets");
   10151                     return -1;
   10152                 }
   10153 
   10154                 // We know we're doing legit work now, so halt the timeout
   10155                 // until we're done.  It gets started again when the result
   10156                 // comes in.
   10157                 mBackupHandler.removeMessages(MSG_RESTORE_TIMEOUT);
   10158 
   10159                 // spin off the transport request to our service thread
   10160                 mWakelock.acquire();
   10161                 Message msg = mBackupHandler.obtainMessage(MSG_RUN_GET_RESTORE_SETS,
   10162                         new RestoreGetSetsParams(mRestoreTransport, this, observer));
   10163                 mBackupHandler.sendMessage(msg);
   10164                 return 0;
   10165             } catch (Exception e) {
   10166                 Slog.e(TAG, "Error in getAvailableRestoreSets", e);
   10167                 return -1;
   10168             } finally {
   10169                 Binder.restoreCallingIdentity(oldId);
   10170             }
   10171         }
   10172 
   10173         public synchronized int restoreAll(long token, IRestoreObserver observer) {
   10174             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   10175                     "performRestore");
   10176 
   10177             if (DEBUG) Slog.d(TAG, "restoreAll token=" + Long.toHexString(token)
   10178                     + " observer=" + observer);
   10179 
   10180             if (mEnded) {
   10181                 throw new IllegalStateException("Restore session already ended");
   10182             }
   10183 
   10184             if (mTimedOut) {
   10185                 Slog.i(TAG, "Session already timed out");
   10186                 return -1;
   10187             }
   10188 
   10189             if (mRestoreTransport == null || mRestoreSets == null) {
   10190                 Slog.e(TAG, "Ignoring restoreAll() with no restore set");
   10191                 return -1;
   10192             }
   10193 
   10194             if (mPackageName != null) {
   10195                 Slog.e(TAG, "Ignoring restoreAll() on single-package session");
   10196                 return -1;
   10197             }
   10198 
   10199             String dirName;
   10200             try {
   10201                 dirName = mRestoreTransport.transportDirName();
   10202             } catch (Exception e) {
   10203                 // Transport went AWOL; fail.
   10204                 Slog.e(TAG, "Unable to get transport dir for restore: " + e.getMessage());
   10205                 return -1;
   10206             }
   10207 
   10208             synchronized (mQueueLock) {
   10209                 for (int i = 0; i < mRestoreSets.length; i++) {
   10210                     if (token == mRestoreSets[i].token) {
   10211                         // Real work, so stop the session timeout until we finalize the restore
   10212                         mBackupHandler.removeMessages(MSG_RESTORE_TIMEOUT);
   10213 
   10214                         long oldId = Binder.clearCallingIdentity();
   10215                         mWakelock.acquire();
   10216                         if (MORE_DEBUG) {
   10217                             Slog.d(TAG, "restoreAll() kicking off");
   10218                         }
   10219                         Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
   10220                         msg.obj = new RestoreParams(mRestoreTransport, dirName,
   10221                                 observer, token);
   10222                         mBackupHandler.sendMessage(msg);
   10223                         Binder.restoreCallingIdentity(oldId);
   10224                         return 0;
   10225                     }
   10226                 }
   10227             }
   10228 
   10229             Slog.w(TAG, "Restore token " + Long.toHexString(token) + " not found");
   10230             return -1;
   10231         }
   10232 
   10233         // Restores of more than a single package are treated as 'system' restores
   10234         public synchronized int restoreSome(long token, IRestoreObserver observer,
   10235                 String[] packages) {
   10236             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   10237                     "performRestore");
   10238 
   10239             if (DEBUG) {
   10240                 StringBuilder b = new StringBuilder(128);
   10241                 b.append("restoreSome token=");
   10242                 b.append(Long.toHexString(token));
   10243                 b.append(" observer=");
   10244                 b.append(observer.toString());
   10245                 b.append(" packages=");
   10246                 if (packages == null) {
   10247                     b.append("null");
   10248                 } else {
   10249                     b.append('{');
   10250                     boolean first = true;
   10251                     for (String s : packages) {
   10252                         if (!first) {
   10253                             b.append(", ");
   10254                         } else first = false;
   10255                         b.append(s);
   10256                     }
   10257                     b.append('}');
   10258                 }
   10259                 Slog.d(TAG, b.toString());
   10260             }
   10261 
   10262             if (mEnded) {
   10263                 throw new IllegalStateException("Restore session already ended");
   10264             }
   10265 
   10266             if (mTimedOut) {
   10267                 Slog.i(TAG, "Session already timed out");
   10268                 return -1;
   10269             }
   10270 
   10271             if (mRestoreTransport == null || mRestoreSets == null) {
   10272                 Slog.e(TAG, "Ignoring restoreAll() with no restore set");
   10273                 return -1;
   10274             }
   10275 
   10276             if (mPackageName != null) {
   10277                 Slog.e(TAG, "Ignoring restoreAll() on single-package session");
   10278                 return -1;
   10279             }
   10280 
   10281             String dirName;
   10282             try {
   10283                 dirName = mRestoreTransport.transportDirName();
   10284             } catch (Exception e) {
   10285                 // Transport went AWOL; fail.
   10286                 Slog.e(TAG, "Unable to get transport name for restoreSome: " + e.getMessage());
   10287                 return -1;
   10288             }
   10289 
   10290             synchronized (mQueueLock) {
   10291                 for (int i = 0; i < mRestoreSets.length; i++) {
   10292                     if (token == mRestoreSets[i].token) {
   10293                         // Stop the session timeout until we finalize the restore
   10294                         mBackupHandler.removeMessages(MSG_RESTORE_TIMEOUT);
   10295 
   10296                         long oldId = Binder.clearCallingIdentity();
   10297                         mWakelock.acquire();
   10298                         if (MORE_DEBUG) {
   10299                             Slog.d(TAG, "restoreSome() of " + packages.length + " packages");
   10300                         }
   10301                         Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
   10302                         msg.obj = new RestoreParams(mRestoreTransport, dirName, observer, token,
   10303                                 packages, packages.length > 1);
   10304                         mBackupHandler.sendMessage(msg);
   10305                         Binder.restoreCallingIdentity(oldId);
   10306                         return 0;
   10307                     }
   10308                 }
   10309             }
   10310 
   10311             Slog.w(TAG, "Restore token " + Long.toHexString(token) + " not found");
   10312             return -1;
   10313         }
   10314 
   10315         public synchronized int restorePackage(String packageName, IRestoreObserver observer) {
   10316             if (DEBUG) Slog.v(TAG, "restorePackage pkg=" + packageName + " obs=" + observer);
   10317 
   10318             if (mEnded) {
   10319                 throw new IllegalStateException("Restore session already ended");
   10320             }
   10321 
   10322             if (mTimedOut) {
   10323                 Slog.i(TAG, "Session already timed out");
   10324                 return -1;
   10325             }
   10326 
   10327             if (mPackageName != null) {
   10328                 if (! mPackageName.equals(packageName)) {
   10329                     Slog.e(TAG, "Ignoring attempt to restore pkg=" + packageName
   10330                             + " on session for package " + mPackageName);
   10331                     return -1;
   10332                 }
   10333             }
   10334 
   10335             PackageInfo app = null;
   10336             try {
   10337                 app = mPackageManager.getPackageInfo(packageName, 0);
   10338             } catch (NameNotFoundException nnf) {
   10339                 Slog.w(TAG, "Asked to restore nonexistent pkg " + packageName);
   10340                 return -1;
   10341             }
   10342 
   10343             // If the caller is not privileged and is not coming from the target
   10344             // app's uid, throw a permission exception back to the caller.
   10345             int perm = mContext.checkPermission(android.Manifest.permission.BACKUP,
   10346                     Binder.getCallingPid(), Binder.getCallingUid());
   10347             if ((perm == PackageManager.PERMISSION_DENIED) &&
   10348                     (app.applicationInfo.uid != Binder.getCallingUid())) {
   10349                 Slog.w(TAG, "restorePackage: bad packageName=" + packageName
   10350                         + " or calling uid=" + Binder.getCallingUid());
   10351                 throw new SecurityException("No permission to restore other packages");
   10352             }
   10353 
   10354             // So far so good; we're allowed to try to restore this package.
   10355             long oldId = Binder.clearCallingIdentity();
   10356             try {
   10357                 // Check whether there is data for it in the current dataset, falling back
   10358                 // to the ancestral dataset if not.
   10359                 long token = getAvailableRestoreToken(packageName);
   10360                 if (DEBUG) Slog.v(TAG, "restorePackage pkg=" + packageName
   10361                         + " token=" + Long.toHexString(token));
   10362 
   10363                 // If we didn't come up with a place to look -- no ancestral dataset and
   10364                 // the app has never been backed up from this device -- there's nothing
   10365                 // to do but return failure.
   10366                 if (token == 0) {
   10367                     if (DEBUG) Slog.w(TAG, "No data available for this package; not restoring");
   10368                     return -1;
   10369                 }
   10370 
   10371                 String dirName;
   10372                 try {
   10373                     dirName = mRestoreTransport.transportDirName();
   10374                 } catch (Exception e) {
   10375                     // Transport went AWOL; fail.
   10376                     Slog.e(TAG, "Unable to get transport dir for restorePackage: " + e.getMessage());
   10377                     return -1;
   10378                 }
   10379 
   10380                 // Stop the session timeout until we finalize the restore
   10381                 mBackupHandler.removeMessages(MSG_RESTORE_TIMEOUT);
   10382 
   10383                 // Ready to go:  enqueue the restore request and claim success
   10384                 mWakelock.acquire();
   10385                 if (MORE_DEBUG) {
   10386                     Slog.d(TAG, "restorePackage() : " + packageName);
   10387                 }
   10388                 Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
   10389                 msg.obj = new RestoreParams(mRestoreTransport, dirName, observer, token, app);
   10390                 mBackupHandler.sendMessage(msg);
   10391             } finally {
   10392                 Binder.restoreCallingIdentity(oldId);
   10393             }
   10394             return 0;
   10395         }
   10396 
   10397         // Posted to the handler to tear down a restore session in a cleanly synchronized way
   10398         class EndRestoreRunnable implements Runnable {
   10399             BackupManagerService mBackupManager;
   10400             ActiveRestoreSession mSession;
   10401 
   10402             EndRestoreRunnable(BackupManagerService manager, ActiveRestoreSession session) {
   10403                 mBackupManager = manager;
   10404                 mSession = session;
   10405             }
   10406 
   10407             public void run() {
   10408                 // clean up the session's bookkeeping
   10409                 synchronized (mSession) {
   10410                     mSession.mRestoreTransport = null;
   10411                     mSession.mEnded = true;
   10412                 }
   10413 
   10414                 // clean up the BackupManagerImpl side of the bookkeeping
   10415                 // and cancel any pending timeout message
   10416                 mBackupManager.clearRestoreSession(mSession);
   10417             }
   10418         }
   10419 
   10420         public synchronized void endRestoreSession() {
   10421             if (DEBUG) Slog.d(TAG, "endRestoreSession");
   10422 
   10423             if (mTimedOut) {
   10424                 Slog.i(TAG, "Session already timed out");
   10425                 return;
   10426             }
   10427 
   10428             if (mEnded) {
   10429                 throw new IllegalStateException("Restore session already ended");
   10430             }
   10431 
   10432             mBackupHandler.post(new EndRestoreRunnable(BackupManagerService.this, this));
   10433         }
   10434     }
   10435 
   10436     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   10437         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
   10438 
   10439         long identityToken = Binder.clearCallingIdentity();
   10440         try {
   10441             if (args != null) {
   10442                 for (String arg : args) {
   10443                     if ("-h".equals(arg)) {
   10444                         pw.println("'dumpsys backup' optional arguments:");
   10445                         pw.println("  -h       : this help text");
   10446                         pw.println("  a[gents] : dump information about defined backup agents");
   10447                         return;
   10448                     } else if ("agents".startsWith(arg)) {
   10449                         dumpAgents(pw);
   10450                         return;
   10451                     }
   10452                 }
   10453             }
   10454             dumpInternal(pw);
   10455         } finally {
   10456             Binder.restoreCallingIdentity(identityToken);
   10457         }
   10458     }
   10459 
   10460     private void dumpAgents(PrintWriter pw) {
   10461         List<PackageInfo> agentPackages = allAgentPackages();
   10462         pw.println("Defined backup agents:");
   10463         for (PackageInfo pkg : agentPackages) {
   10464             pw.print("  ");
   10465             pw.print(pkg.packageName); pw.println(':');
   10466             pw.print("      "); pw.println(pkg.applicationInfo.backupAgentName);
   10467         }
   10468     }
   10469 
   10470     private void dumpInternal(PrintWriter pw) {
   10471         synchronized (mQueueLock) {
   10472             pw.println("Backup Manager is " + (mEnabled ? "enabled" : "disabled")
   10473                     + " / " + (!mProvisioned ? "not " : "") + "provisioned / "
   10474                     + (this.mPendingInits.size() == 0 ? "not " : "") + "pending init");
   10475             pw.println("Auto-restore is " + (mAutoRestore ? "enabled" : "disabled"));
   10476             if (mBackupRunning) pw.println("Backup currently running");
   10477             pw.println("Last backup pass started: " + mLastBackupPass
   10478                     + " (now = " + System.currentTimeMillis() + ')');
   10479             pw.println("  next scheduled: " + KeyValueBackupJob.nextScheduled());
   10480 
   10481             pw.println("Transport whitelist:");
   10482             for (ComponentName transport : mTransportWhitelist) {
   10483                 pw.print("    ");
   10484                 pw.println(transport.flattenToShortString());
   10485             }
   10486 
   10487             pw.println("Available transports:");
   10488             final String[] transports = listAllTransports();
   10489             if (transports != null) {
   10490                 for (String t : listAllTransports()) {
   10491                     pw.println((t.equals(mCurrentTransport) ? "  * " : "    ") + t);
   10492                     try {
   10493                         IBackupTransport transport = getTransport(t);
   10494                         File dir = new File(mBaseStateDir, transport.transportDirName());
   10495                         pw.println("       destination: " + transport.currentDestinationString());
   10496                         pw.println("       intent: " + transport.configurationIntent());
   10497                         for (File f : dir.listFiles()) {
   10498                             pw.println("       " + f.getName() + " - " + f.length() + " state bytes");
   10499                         }
   10500                     } catch (Exception e) {
   10501                         Slog.e(TAG, "Error in transport", e);
   10502                         pw.println("        Error: " + e);
   10503                     }
   10504                 }
   10505             }
   10506 
   10507             pw.println("Pending init: " + mPendingInits.size());
   10508             for (String s : mPendingInits) {
   10509                 pw.println("    " + s);
   10510             }
   10511 
   10512             if (DEBUG_BACKUP_TRACE) {
   10513                 synchronized (mBackupTrace) {
   10514                     if (!mBackupTrace.isEmpty()) {
   10515                         pw.println("Most recent backup trace:");
   10516                         for (String s : mBackupTrace) {
   10517                             pw.println("   " + s);
   10518                         }
   10519                     }
   10520                 }
   10521             }
   10522 
   10523             pw.print("Ancestral: "); pw.println(Long.toHexString(mAncestralToken));
   10524             pw.print("Current:   "); pw.println(Long.toHexString(mCurrentToken));
   10525 
   10526             int N = mBackupParticipants.size();
   10527             pw.println("Participants:");
   10528             for (int i=0; i<N; i++) {
   10529                 int uid = mBackupParticipants.keyAt(i);
   10530                 pw.print("  uid: ");
   10531                 pw.println(uid);
   10532                 HashSet<String> participants = mBackupParticipants.valueAt(i);
   10533                 for (String app: participants) {
   10534                     pw.println("    " + app);
   10535                 }
   10536             }
   10537 
   10538             pw.println("Ancestral packages: "
   10539                     + (mAncestralPackages == null ? "none" : mAncestralPackages.size()));
   10540             if (mAncestralPackages != null) {
   10541                 for (String pkg : mAncestralPackages) {
   10542                     pw.println("    " + pkg);
   10543                 }
   10544             }
   10545 
   10546             pw.println("Ever backed up: " + mEverStoredApps.size());
   10547             for (String pkg : mEverStoredApps) {
   10548                 pw.println("    " + pkg);
   10549             }
   10550 
   10551             pw.println("Pending key/value backup: " + mPendingBackups.size());
   10552             for (BackupRequest req : mPendingBackups.values()) {
   10553                 pw.println("    " + req);
   10554             }
   10555 
   10556             pw.println("Full backup queue:" + mFullBackupQueue.size());
   10557             for (FullBackupEntry entry : mFullBackupQueue) {
   10558                 pw.print("    "); pw.print(entry.lastBackup);
   10559                 pw.print(" : "); pw.println(entry.packageName);
   10560             }
   10561         }
   10562     }
   10563 
   10564     private static void sendBackupOnUpdate(IBackupObserver observer, String packageName,
   10565             BackupProgress progress) {
   10566         if (observer != null) {
   10567             try {
   10568                 observer.onUpdate(packageName, progress);
   10569             } catch (RemoteException e) {
   10570                 if (DEBUG) {
   10571                     Slog.w(TAG, "Backup observer went away: onUpdate");
   10572                 }
   10573             }
   10574         }
   10575     }
   10576 
   10577     private static void sendBackupOnPackageResult(IBackupObserver observer, String packageName,
   10578             int status) {
   10579         if (observer != null) {
   10580             try {
   10581                 observer.onResult(packageName, status);
   10582             } catch (RemoteException e) {
   10583                 if (DEBUG) {
   10584                     Slog.w(TAG, "Backup observer went away: onResult");
   10585                 }
   10586             }
   10587         }
   10588     }
   10589 
   10590     private static void sendBackupFinished(IBackupObserver observer, int status) {
   10591         if (observer != null) {
   10592             try {
   10593                 observer.backupFinished(status);
   10594             } catch (RemoteException e) {
   10595                 if (DEBUG) {
   10596                     Slog.w(TAG, "Backup observer went away: backupFinished");
   10597                 }
   10598             }
   10599         }
   10600     }
   10601 }
   10602