Home | History | Annotate | Download | only in server
      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;
     18 
     19 import android.app.ActivityManagerNative;
     20 import android.app.AlarmManager;
     21 import android.app.AppGlobals;
     22 import android.app.IActivityManager;
     23 import android.app.IApplicationThread;
     24 import android.app.IBackupAgent;
     25 import android.app.PendingIntent;
     26 import android.app.backup.BackupAgent;
     27 import android.app.backup.BackupDataOutput;
     28 import android.app.backup.FullBackup;
     29 import android.app.backup.RestoreSet;
     30 import android.app.backup.IBackupManager;
     31 import android.app.backup.IFullBackupRestoreObserver;
     32 import android.app.backup.IRestoreObserver;
     33 import android.app.backup.IRestoreSession;
     34 import android.content.ActivityNotFoundException;
     35 import android.content.BroadcastReceiver;
     36 import android.content.ComponentName;
     37 import android.content.ContentResolver;
     38 import android.content.Context;
     39 import android.content.Intent;
     40 import android.content.IntentFilter;
     41 import android.content.ServiceConnection;
     42 import android.content.pm.ApplicationInfo;
     43 import android.content.pm.IPackageDataObserver;
     44 import android.content.pm.IPackageDeleteObserver;
     45 import android.content.pm.IPackageInstallObserver;
     46 import android.content.pm.IPackageManager;
     47 import android.content.pm.PackageInfo;
     48 import android.content.pm.PackageManager;
     49 import android.content.pm.ResolveInfo;
     50 import android.content.pm.ServiceInfo;
     51 import android.content.pm.Signature;
     52 import android.content.pm.PackageManager.NameNotFoundException;
     53 import android.database.ContentObserver;
     54 import android.net.Uri;
     55 import android.os.Binder;
     56 import android.os.Build;
     57 import android.os.Bundle;
     58 import android.os.Environment;
     59 import android.os.Handler;
     60 import android.os.HandlerThread;
     61 import android.os.IBinder;
     62 import android.os.Looper;
     63 import android.os.Message;
     64 import android.os.ParcelFileDescriptor;
     65 import android.os.PowerManager;
     66 import android.os.Process;
     67 import android.os.RemoteException;
     68 import android.os.SELinux;
     69 import android.os.ServiceManager;
     70 import android.os.SystemClock;
     71 import android.os.UserHandle;
     72 import android.os.WorkSource;
     73 import android.os.Environment.UserEnvironment;
     74 import android.os.storage.IMountService;
     75 import android.provider.Settings;
     76 import android.util.EventLog;
     77 import android.util.Log;
     78 import android.util.Slog;
     79 import android.util.SparseArray;
     80 import android.util.StringBuilderPrinter;
     81 
     82 import com.android.internal.backup.BackupConstants;
     83 import com.android.internal.backup.IBackupTransport;
     84 import com.android.internal.backup.IObbBackupService;
     85 import com.android.internal.backup.LocalTransport;
     86 import com.android.server.PackageManagerBackupAgent.Metadata;
     87 
     88 import java.io.BufferedInputStream;
     89 import java.io.BufferedOutputStream;
     90 import java.io.ByteArrayOutputStream;
     91 import java.io.DataInputStream;
     92 import java.io.DataOutputStream;
     93 import java.io.EOFException;
     94 import java.io.File;
     95 import java.io.FileDescriptor;
     96 import java.io.FileInputStream;
     97 import java.io.FileNotFoundException;
     98 import java.io.FileOutputStream;
     99 import java.io.IOException;
    100 import java.io.InputStream;
    101 import java.io.OutputStream;
    102 import java.io.PrintWriter;
    103 import java.io.RandomAccessFile;
    104 import java.security.InvalidAlgorithmParameterException;
    105 import java.security.InvalidKeyException;
    106 import java.security.Key;
    107 import java.security.NoSuchAlgorithmException;
    108 import java.security.SecureRandom;
    109 import java.security.spec.InvalidKeySpecException;
    110 import java.security.spec.KeySpec;
    111 import java.text.SimpleDateFormat;
    112 import java.util.ArrayList;
    113 import java.util.Arrays;
    114 import java.util.Date;
    115 import java.util.HashMap;
    116 import java.util.HashSet;
    117 import java.util.List;
    118 import java.util.Map;
    119 import java.util.Random;
    120 import java.util.Set;
    121 import java.util.concurrent.atomic.AtomicBoolean;
    122 import java.util.zip.Deflater;
    123 import java.util.zip.DeflaterOutputStream;
    124 import java.util.zip.InflaterInputStream;
    125 
    126 import javax.crypto.BadPaddingException;
    127 import javax.crypto.Cipher;
    128 import javax.crypto.CipherInputStream;
    129 import javax.crypto.CipherOutputStream;
    130 import javax.crypto.IllegalBlockSizeException;
    131 import javax.crypto.NoSuchPaddingException;
    132 import javax.crypto.SecretKey;
    133 import javax.crypto.SecretKeyFactory;
    134 import javax.crypto.spec.IvParameterSpec;
    135 import javax.crypto.spec.PBEKeySpec;
    136 import javax.crypto.spec.SecretKeySpec;
    137 
    138 class BackupManagerService extends IBackupManager.Stub {
    139     private static final String TAG = "BackupManagerService";
    140     private static final boolean DEBUG = true;
    141     private static final boolean MORE_DEBUG = false;
    142 
    143     // Name and current contents version of the full-backup manifest file
    144     static final String BACKUP_MANIFEST_FILENAME = "_manifest";
    145     static final int BACKUP_MANIFEST_VERSION = 1;
    146     static final String BACKUP_FILE_HEADER_MAGIC = "ANDROID BACKUP\n";
    147     static final int BACKUP_FILE_VERSION = 1;
    148     static final boolean COMPRESS_FULL_BACKUPS = true; // should be true in production
    149 
    150     static final String SHARED_BACKUP_AGENT_PACKAGE = "com.android.sharedstoragebackup";
    151     static final String SERVICE_ACTION_TRANSPORT_HOST = "android.backup.TRANSPORT_HOST";
    152 
    153     // How often we perform a backup pass.  Privileged external callers can
    154     // trigger an immediate pass.
    155     private static final long BACKUP_INTERVAL = AlarmManager.INTERVAL_HOUR;
    156 
    157     // Random variation in backup scheduling time to avoid server load spikes
    158     private static final int FUZZ_MILLIS = 5 * 60 * 1000;
    159 
    160     // The amount of time between the initial provisioning of the device and
    161     // the first backup pass.
    162     private static final long FIRST_BACKUP_INTERVAL = 12 * AlarmManager.INTERVAL_HOUR;
    163 
    164     // Retry interval for clear/init when the transport is unavailable
    165     private static final long TRANSPORT_RETRY_INTERVAL = 1 * AlarmManager.INTERVAL_HOUR;
    166 
    167     private static final String RUN_BACKUP_ACTION = "android.app.backup.intent.RUN";
    168     private static final String RUN_INITIALIZE_ACTION = "android.app.backup.intent.INIT";
    169     private static final String RUN_CLEAR_ACTION = "android.app.backup.intent.CLEAR";
    170     private static final int MSG_RUN_BACKUP = 1;
    171     private static final int MSG_RUN_FULL_BACKUP = 2;
    172     private static final int MSG_RUN_RESTORE = 3;
    173     private static final int MSG_RUN_CLEAR = 4;
    174     private static final int MSG_RUN_INITIALIZE = 5;
    175     private static final int MSG_RUN_GET_RESTORE_SETS = 6;
    176     private static final int MSG_TIMEOUT = 7;
    177     private static final int MSG_RESTORE_TIMEOUT = 8;
    178     private static final int MSG_FULL_CONFIRMATION_TIMEOUT = 9;
    179     private static final int MSG_RUN_FULL_RESTORE = 10;
    180     private static final int MSG_RETRY_INIT = 11;
    181     private static final int MSG_RETRY_CLEAR = 12;
    182 
    183     // backup task state machine tick
    184     static final int MSG_BACKUP_RESTORE_STEP = 20;
    185     static final int MSG_OP_COMPLETE = 21;
    186 
    187     // Timeout interval for deciding that a bind or clear-data has taken too long
    188     static final long TIMEOUT_INTERVAL = 10 * 1000;
    189 
    190     // Timeout intervals for agent backup & restore operations
    191     static final long TIMEOUT_BACKUP_INTERVAL = 30 * 1000;
    192     static final long TIMEOUT_FULL_BACKUP_INTERVAL = 5 * 60 * 1000;
    193     static final long TIMEOUT_SHARED_BACKUP_INTERVAL = 30 * 60 * 1000;
    194     static final long TIMEOUT_RESTORE_INTERVAL = 60 * 1000;
    195 
    196     // User confirmation timeout for a full backup/restore operation.  It's this long in
    197     // order to give them time to enter the backup password.
    198     static final long TIMEOUT_FULL_CONFIRMATION = 60 * 1000;
    199 
    200     private Context mContext;
    201     private PackageManager mPackageManager;
    202     IPackageManager mPackageManagerBinder;
    203     private IActivityManager mActivityManager;
    204     private PowerManager mPowerManager;
    205     private AlarmManager mAlarmManager;
    206     private IMountService mMountService;
    207     IBackupManager mBackupManagerBinder;
    208 
    209     boolean mEnabled;   // access to this is synchronized on 'this'
    210     boolean mProvisioned;
    211     boolean mAutoRestore;
    212     PowerManager.WakeLock mWakelock;
    213     HandlerThread mHandlerThread;
    214     BackupHandler mBackupHandler;
    215     PendingIntent mRunBackupIntent, mRunInitIntent;
    216     BroadcastReceiver mRunBackupReceiver, mRunInitReceiver;
    217     // map UIDs to the set of participating packages under that UID
    218     final SparseArray<HashSet<String>> mBackupParticipants
    219             = new SparseArray<HashSet<String>>();
    220     // set of backup services that have pending changes
    221     class BackupRequest {
    222         public String packageName;
    223 
    224         BackupRequest(String pkgName) {
    225             packageName = pkgName;
    226         }
    227 
    228         public String toString() {
    229             return "BackupRequest{pkg=" + packageName + "}";
    230         }
    231     }
    232     // Backups that we haven't started yet.  Keys are package names.
    233     HashMap<String,BackupRequest> mPendingBackups
    234             = new HashMap<String,BackupRequest>();
    235 
    236     // Pseudoname that we use for the Package Manager metadata "package"
    237     static final String PACKAGE_MANAGER_SENTINEL = "@pm@";
    238 
    239     // locking around the pending-backup management
    240     final Object mQueueLock = new Object();
    241 
    242     // The thread performing the sequence of queued backups binds to each app's agent
    243     // in succession.  Bind notifications are asynchronously delivered through the
    244     // Activity Manager; use this lock object to signal when a requested binding has
    245     // completed.
    246     final Object mAgentConnectLock = new Object();
    247     IBackupAgent mConnectedAgent;
    248     volatile boolean mBackupRunning;
    249     volatile boolean mConnecting;
    250     volatile long mLastBackupPass;
    251     volatile long mNextBackupPass;
    252 
    253     // For debugging, we maintain a progress trace of operations during backup
    254     static final boolean DEBUG_BACKUP_TRACE = true;
    255     final List<String> mBackupTrace = new ArrayList<String>();
    256 
    257     // A similar synchronization mechanism around clearing apps' data for restore
    258     final Object mClearDataLock = new Object();
    259     volatile boolean mClearingData;
    260 
    261     // Transport bookkeeping
    262     final HashMap<String,String> mTransportNames
    263             = new HashMap<String,String>();             // component name -> registration name
    264     final HashMap<String,IBackupTransport> mTransports
    265             = new HashMap<String,IBackupTransport>();   // registration name -> binder
    266     final ArrayList<TransportConnection> mTransportConnections
    267             = new ArrayList<TransportConnection>();
    268     String mCurrentTransport;
    269     ActiveRestoreSession mActiveRestoreSession;
    270 
    271     // Watch the device provisioning operation during setup
    272     ContentObserver mProvisionedObserver;
    273 
    274     class ProvisionedObserver extends ContentObserver {
    275         public ProvisionedObserver(Handler handler) {
    276             super(handler);
    277         }
    278 
    279         public void onChange(boolean selfChange) {
    280             final boolean wasProvisioned = mProvisioned;
    281             final boolean isProvisioned = deviceIsProvisioned();
    282             // latch: never unprovision
    283             mProvisioned = wasProvisioned || isProvisioned;
    284             if (MORE_DEBUG) {
    285                 Slog.d(TAG, "Provisioning change: was=" + wasProvisioned
    286                         + " is=" + isProvisioned + " now=" + mProvisioned);
    287             }
    288 
    289             synchronized (mQueueLock) {
    290                 if (mProvisioned && !wasProvisioned && mEnabled) {
    291                     // we're now good to go, so start the backup alarms
    292                     if (MORE_DEBUG) Slog.d(TAG, "Now provisioned, so starting backups");
    293                     startBackupAlarmsLocked(FIRST_BACKUP_INTERVAL);
    294                 }
    295             }
    296         }
    297     }
    298 
    299     class RestoreGetSetsParams {
    300         public IBackupTransport transport;
    301         public ActiveRestoreSession session;
    302         public IRestoreObserver observer;
    303 
    304         RestoreGetSetsParams(IBackupTransport _transport, ActiveRestoreSession _session,
    305                 IRestoreObserver _observer) {
    306             transport = _transport;
    307             session = _session;
    308             observer = _observer;
    309         }
    310     }
    311 
    312     class RestoreParams {
    313         public IBackupTransport transport;
    314         public String dirName;
    315         public IRestoreObserver observer;
    316         public long token;
    317         public PackageInfo pkgInfo;
    318         public int pmToken; // in post-install restore, the PM's token for this transaction
    319         public boolean needFullBackup;
    320         public String[] filterSet;
    321 
    322         RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
    323                 long _token, PackageInfo _pkg, int _pmToken, boolean _needFullBackup) {
    324             transport = _transport;
    325             dirName = _dirName;
    326             observer = _obs;
    327             token = _token;
    328             pkgInfo = _pkg;
    329             pmToken = _pmToken;
    330             needFullBackup = _needFullBackup;
    331             filterSet = null;
    332         }
    333 
    334         RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
    335                 long _token, boolean _needFullBackup) {
    336             transport = _transport;
    337             dirName = _dirName;
    338             observer = _obs;
    339             token = _token;
    340             pkgInfo = null;
    341             pmToken = 0;
    342             needFullBackup = _needFullBackup;
    343             filterSet = null;
    344         }
    345 
    346         RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
    347                 long _token, String[] _filterSet, boolean _needFullBackup) {
    348             transport = _transport;
    349             dirName = _dirName;
    350             observer = _obs;
    351             token = _token;
    352             pkgInfo = null;
    353             pmToken = 0;
    354             needFullBackup = _needFullBackup;
    355             filterSet = _filterSet;
    356         }
    357     }
    358 
    359     class ClearParams {
    360         public IBackupTransport transport;
    361         public PackageInfo packageInfo;
    362 
    363         ClearParams(IBackupTransport _transport, PackageInfo _info) {
    364             transport = _transport;
    365             packageInfo = _info;
    366         }
    367     }
    368 
    369     class ClearRetryParams {
    370         public String transportName;
    371         public String packageName;
    372 
    373         ClearRetryParams(String transport, String pkg) {
    374             transportName = transport;
    375             packageName = pkg;
    376         }
    377     }
    378 
    379     class FullParams {
    380         public ParcelFileDescriptor fd;
    381         public final AtomicBoolean latch;
    382         public IFullBackupRestoreObserver observer;
    383         public String curPassword;     // filled in by the confirmation step
    384         public String encryptPassword;
    385 
    386         FullParams() {
    387             latch = new AtomicBoolean(false);
    388         }
    389     }
    390 
    391     class FullBackupParams extends FullParams {
    392         public boolean includeApks;
    393         public boolean includeObbs;
    394         public boolean includeShared;
    395         public boolean allApps;
    396         public boolean includeSystem;
    397         public String[] packages;
    398 
    399         FullBackupParams(ParcelFileDescriptor output, boolean saveApks, boolean saveObbs,
    400                 boolean saveShared, boolean doAllApps, boolean doSystem, String[] pkgList) {
    401             fd = output;
    402             includeApks = saveApks;
    403             includeObbs = saveObbs;
    404             includeShared = saveShared;
    405             allApps = doAllApps;
    406             includeSystem = doSystem;
    407             packages = pkgList;
    408         }
    409     }
    410 
    411     class FullRestoreParams extends FullParams {
    412         FullRestoreParams(ParcelFileDescriptor input) {
    413             fd = input;
    414         }
    415     }
    416 
    417     // Bookkeeping of in-flight operations for timeout etc. purposes.  The operation
    418     // token is the index of the entry in the pending-operations list.
    419     static final int OP_PENDING = 0;
    420     static final int OP_ACKNOWLEDGED = 1;
    421     static final int OP_TIMEOUT = -1;
    422 
    423     class Operation {
    424         public int state;
    425         public BackupRestoreTask callback;
    426 
    427         Operation(int initialState, BackupRestoreTask callbackObj) {
    428             state = initialState;
    429             callback = callbackObj;
    430         }
    431     }
    432     final SparseArray<Operation> mCurrentOperations = new SparseArray<Operation>();
    433     final Object mCurrentOpLock = new Object();
    434     final Random mTokenGenerator = new Random();
    435 
    436     final SparseArray<FullParams> mFullConfirmations = new SparseArray<FullParams>();
    437 
    438     // Where we keep our journal files and other bookkeeping
    439     File mBaseStateDir;
    440     File mDataDir;
    441     File mJournalDir;
    442     File mJournal;
    443 
    444     // Backup password, if any, and the file where it's saved.  What is stored is not the
    445     // password text itself; it's the result of a PBKDF2 hash with a randomly chosen (but
    446     // persisted) salt.  Validation is performed by running the challenge text through the
    447     // same PBKDF2 cycle with the persisted salt; if the resulting derived key string matches
    448     // the saved hash string, then the challenge text matches the originally supplied
    449     // password text.
    450     private final SecureRandom mRng = new SecureRandom();
    451     private String mPasswordHash;
    452     private File mPasswordHashFile;
    453     private byte[] mPasswordSalt;
    454 
    455     // Configuration of PBKDF2 that we use for generating pw hashes and intermediate keys
    456     static final int PBKDF2_HASH_ROUNDS = 10000;
    457     static final int PBKDF2_KEY_SIZE = 256;     // bits
    458     static final int PBKDF2_SALT_SIZE = 512;    // bits
    459     static final String ENCRYPTION_ALGORITHM_NAME = "AES-256";
    460 
    461     // Keep a log of all the apps we've ever backed up, and what the
    462     // dataset tokens are for both the current backup dataset and
    463     // the ancestral dataset.
    464     private File mEverStored;
    465     HashSet<String> mEverStoredApps = new HashSet<String>();
    466 
    467     static final int CURRENT_ANCESTRAL_RECORD_VERSION = 1;  // increment when the schema changes
    468     File mTokenFile;
    469     Set<String> mAncestralPackages = null;
    470     long mAncestralToken = 0;
    471     long mCurrentToken = 0;
    472 
    473     // Persistently track the need to do a full init
    474     static final String INIT_SENTINEL_FILE_NAME = "_need_init_";
    475     HashSet<String> mPendingInits = new HashSet<String>();  // transport names
    476 
    477     // Utility: build a new random integer token
    478     int generateToken() {
    479         int token;
    480         do {
    481             synchronized (mTokenGenerator) {
    482                 token = mTokenGenerator.nextInt();
    483             }
    484         } while (token < 0);
    485         return token;
    486     }
    487 
    488     // ----- Asynchronous backup/restore handler thread -----
    489 
    490     private class BackupHandler extends Handler {
    491         public BackupHandler(Looper looper) {
    492             super(looper);
    493         }
    494 
    495         public void handleMessage(Message msg) {
    496 
    497             switch (msg.what) {
    498             case MSG_RUN_BACKUP:
    499             {
    500                 mLastBackupPass = System.currentTimeMillis();
    501                 mNextBackupPass = mLastBackupPass + BACKUP_INTERVAL;
    502 
    503                 IBackupTransport transport = getTransport(mCurrentTransport);
    504                 if (transport == null) {
    505                     Slog.v(TAG, "Backup requested but no transport available");
    506                     synchronized (mQueueLock) {
    507                         mBackupRunning = false;
    508                     }
    509                     mWakelock.release();
    510                     break;
    511                 }
    512 
    513                 // snapshot the pending-backup set and work on that
    514                 ArrayList<BackupRequest> queue = new ArrayList<BackupRequest>();
    515                 File oldJournal = mJournal;
    516                 synchronized (mQueueLock) {
    517                     // Do we have any work to do?  Construct the work queue
    518                     // then release the synchronization lock to actually run
    519                     // the backup.
    520                     if (mPendingBackups.size() > 0) {
    521                         for (BackupRequest b: mPendingBackups.values()) {
    522                             queue.add(b);
    523                         }
    524                         if (DEBUG) Slog.v(TAG, "clearing pending backups");
    525                         mPendingBackups.clear();
    526 
    527                         // Start a new backup-queue journal file too
    528                         mJournal = null;
    529 
    530                     }
    531                 }
    532 
    533                 // At this point, we have started a new journal file, and the old
    534                 // file identity is being passed to the backup processing task.
    535                 // When it completes successfully, that old journal file will be
    536                 // deleted.  If we crash prior to that, the old journal is parsed
    537                 // at next boot and the journaled requests fulfilled.
    538                 boolean staged = true;
    539                 if (queue.size() > 0) {
    540                     // Spin up a backup state sequence and set it running
    541                     try {
    542                         String dirName = transport.transportDirName();
    543                         PerformBackupTask pbt = new PerformBackupTask(transport, dirName,
    544                                 queue, oldJournal);
    545                         Message pbtMessage = obtainMessage(MSG_BACKUP_RESTORE_STEP, pbt);
    546                         sendMessage(pbtMessage);
    547                     } catch (RemoteException e) {
    548                         // unable to ask the transport its dir name -- transient failure, since
    549                         // the above check succeeded.  Try again next time.
    550                         Slog.e(TAG, "Transport became unavailable attempting backup");
    551                         staged = false;
    552                     }
    553                 } else {
    554                     Slog.v(TAG, "Backup requested but nothing pending");
    555                     staged = false;
    556                 }
    557 
    558                 if (!staged) {
    559                     // if we didn't actually hand off the wakelock, rewind until next time
    560                     synchronized (mQueueLock) {
    561                         mBackupRunning = false;
    562                     }
    563                     mWakelock.release();
    564                 }
    565                 break;
    566             }
    567 
    568             case MSG_BACKUP_RESTORE_STEP:
    569             {
    570                 try {
    571                     BackupRestoreTask task = (BackupRestoreTask) msg.obj;
    572                     if (MORE_DEBUG) Slog.v(TAG, "Got next step for " + task + ", executing");
    573                     task.execute();
    574                 } catch (ClassCastException e) {
    575                     Slog.e(TAG, "Invalid backup task in flight, obj=" + msg.obj);
    576                 }
    577                 break;
    578             }
    579 
    580             case MSG_OP_COMPLETE:
    581             {
    582                 try {
    583                     BackupRestoreTask task = (BackupRestoreTask) msg.obj;
    584                     task.operationComplete();
    585                 } catch (ClassCastException e) {
    586                     Slog.e(TAG, "Invalid completion in flight, obj=" + msg.obj);
    587                 }
    588                 break;
    589             }
    590 
    591             case MSG_RUN_FULL_BACKUP:
    592             {
    593                 // TODO: refactor full backup to be a looper-based state machine
    594                 // similar to normal backup/restore.
    595                 FullBackupParams params = (FullBackupParams)msg.obj;
    596                 PerformFullBackupTask task = new PerformFullBackupTask(params.fd,
    597                         params.observer, params.includeApks, params.includeObbs,
    598                         params.includeShared, params.curPassword, params.encryptPassword,
    599                         params.allApps, params.includeSystem, params.packages, params.latch);
    600                 (new Thread(task)).start();
    601                 break;
    602             }
    603 
    604             case MSG_RUN_RESTORE:
    605             {
    606                 RestoreParams params = (RestoreParams)msg.obj;
    607                 Slog.d(TAG, "MSG_RUN_RESTORE observer=" + params.observer);
    608                 PerformRestoreTask task = new PerformRestoreTask(
    609                         params.transport, params.dirName, params.observer,
    610                         params.token, params.pkgInfo, params.pmToken,
    611                         params.needFullBackup, params.filterSet);
    612                 Message restoreMsg = obtainMessage(MSG_BACKUP_RESTORE_STEP, task);
    613                 sendMessage(restoreMsg);
    614                 break;
    615             }
    616 
    617             case MSG_RUN_FULL_RESTORE:
    618             {
    619                 // TODO: refactor full restore to be a looper-based state machine
    620                 // similar to normal backup/restore.
    621                 FullRestoreParams params = (FullRestoreParams)msg.obj;
    622                 PerformFullRestoreTask task = new PerformFullRestoreTask(params.fd,
    623                         params.curPassword, params.encryptPassword,
    624                         params.observer, params.latch);
    625                 (new Thread(task)).start();
    626                 break;
    627             }
    628 
    629             case MSG_RUN_CLEAR:
    630             {
    631                 ClearParams params = (ClearParams)msg.obj;
    632                 (new PerformClearTask(params.transport, params.packageInfo)).run();
    633                 break;
    634             }
    635 
    636             case MSG_RETRY_CLEAR:
    637             {
    638                 // reenqueues if the transport remains unavailable
    639                 ClearRetryParams params = (ClearRetryParams)msg.obj;
    640                 clearBackupData(params.transportName, params.packageName);
    641                 break;
    642             }
    643 
    644             case MSG_RUN_INITIALIZE:
    645             {
    646                 HashSet<String> queue;
    647 
    648                 // Snapshot the pending-init queue and work on that
    649                 synchronized (mQueueLock) {
    650                     queue = new HashSet<String>(mPendingInits);
    651                     mPendingInits.clear();
    652                 }
    653 
    654                 (new PerformInitializeTask(queue)).run();
    655                 break;
    656             }
    657 
    658             case MSG_RETRY_INIT:
    659             {
    660                 synchronized (mQueueLock) {
    661                     recordInitPendingLocked(msg.arg1 != 0, (String)msg.obj);
    662                     mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
    663                             mRunInitIntent);
    664                 }
    665                 break;
    666             }
    667 
    668             case MSG_RUN_GET_RESTORE_SETS:
    669             {
    670                 // Like other async operations, this is entered with the wakelock held
    671                 RestoreSet[] sets = null;
    672                 RestoreGetSetsParams params = (RestoreGetSetsParams)msg.obj;
    673                 try {
    674                     sets = params.transport.getAvailableRestoreSets();
    675                     // cache the result in the active session
    676                     synchronized (params.session) {
    677                         params.session.mRestoreSets = sets;
    678                     }
    679                     if (sets == null) EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
    680                 } catch (Exception e) {
    681                     Slog.e(TAG, "Error from transport getting set list");
    682                 } finally {
    683                     if (params.observer != null) {
    684                         try {
    685                             params.observer.restoreSetsAvailable(sets);
    686                         } catch (RemoteException re) {
    687                             Slog.e(TAG, "Unable to report listing to observer");
    688                         } catch (Exception e) {
    689                             Slog.e(TAG, "Restore observer threw", e);
    690                         }
    691                     }
    692 
    693                     // Done: reset the session timeout clock
    694                     removeMessages(MSG_RESTORE_TIMEOUT);
    695                     sendEmptyMessageDelayed(MSG_RESTORE_TIMEOUT, TIMEOUT_RESTORE_INTERVAL);
    696 
    697                     mWakelock.release();
    698                 }
    699                 break;
    700             }
    701 
    702             case MSG_TIMEOUT:
    703             {
    704                 handleTimeout(msg.arg1, msg.obj);
    705                 break;
    706             }
    707 
    708             case MSG_RESTORE_TIMEOUT:
    709             {
    710                 synchronized (BackupManagerService.this) {
    711                     if (mActiveRestoreSession != null) {
    712                         // Client app left the restore session dangling.  We know that it
    713                         // can't be in the middle of an actual restore operation because
    714                         // the timeout is suspended while a restore is in progress.  Clean
    715                         // up now.
    716                         Slog.w(TAG, "Restore session timed out; aborting");
    717                         post(mActiveRestoreSession.new EndRestoreRunnable(
    718                                 BackupManagerService.this, mActiveRestoreSession));
    719                     }
    720                 }
    721             }
    722 
    723             case MSG_FULL_CONFIRMATION_TIMEOUT:
    724             {
    725                 synchronized (mFullConfirmations) {
    726                     FullParams params = mFullConfirmations.get(msg.arg1);
    727                     if (params != null) {
    728                         Slog.i(TAG, "Full backup/restore timed out waiting for user confirmation");
    729 
    730                         // Release the waiter; timeout == completion
    731                         signalFullBackupRestoreCompletion(params);
    732 
    733                         // Remove the token from the set
    734                         mFullConfirmations.delete(msg.arg1);
    735 
    736                         // Report a timeout to the observer, if any
    737                         if (params.observer != null) {
    738                             try {
    739                                 params.observer.onTimeout();
    740                             } catch (RemoteException e) {
    741                                 /* don't care if the app has gone away */
    742                             }
    743                         }
    744                     } else {
    745                         Slog.d(TAG, "couldn't find params for token " + msg.arg1);
    746                     }
    747                 }
    748                 break;
    749             }
    750             }
    751         }
    752     }
    753 
    754     // ----- Debug-only backup operation trace -----
    755     void addBackupTrace(String s) {
    756         if (DEBUG_BACKUP_TRACE) {
    757             synchronized (mBackupTrace) {
    758                 mBackupTrace.add(s);
    759             }
    760         }
    761     }
    762 
    763     void clearBackupTrace() {
    764         if (DEBUG_BACKUP_TRACE) {
    765             synchronized (mBackupTrace) {
    766                 mBackupTrace.clear();
    767             }
    768         }
    769     }
    770 
    771     // ----- Main service implementation -----
    772 
    773     public BackupManagerService(Context context) {
    774         mContext = context;
    775         mPackageManager = context.getPackageManager();
    776         mPackageManagerBinder = AppGlobals.getPackageManager();
    777         mActivityManager = ActivityManagerNative.getDefault();
    778 
    779         mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    780         mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
    781         mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
    782 
    783         mBackupManagerBinder = asInterface(asBinder());
    784 
    785         // spin up the backup/restore handler thread
    786         mHandlerThread = new HandlerThread("backup", Process.THREAD_PRIORITY_BACKGROUND);
    787         mHandlerThread.start();
    788         mBackupHandler = new BackupHandler(mHandlerThread.getLooper());
    789 
    790         // Set up our bookkeeping
    791         final ContentResolver resolver = context.getContentResolver();
    792         boolean areEnabled = Settings.Secure.getInt(resolver,
    793                 Settings.Secure.BACKUP_ENABLED, 0) != 0;
    794         mProvisioned = Settings.Global.getInt(resolver,
    795                 Settings.Global.DEVICE_PROVISIONED, 0) != 0;
    796         mAutoRestore = Settings.Secure.getInt(resolver,
    797                 Settings.Secure.BACKUP_AUTO_RESTORE, 1) != 0;
    798 
    799         mProvisionedObserver = new ProvisionedObserver(mBackupHandler);
    800         resolver.registerContentObserver(
    801                 Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED),
    802                 false, mProvisionedObserver);
    803 
    804         // If Encrypted file systems is enabled or disabled, this call will return the
    805         // correct directory.
    806         mBaseStateDir = new File(Environment.getSecureDataDirectory(), "backup");
    807         mBaseStateDir.mkdirs();
    808         if (!SELinux.restorecon(mBaseStateDir)) {
    809             Slog.e(TAG, "SELinux restorecon failed on " + mBaseStateDir);
    810         }
    811         mDataDir = Environment.getDownloadCacheDirectory();
    812 
    813         mPasswordHashFile = new File(mBaseStateDir, "pwhash");
    814         if (mPasswordHashFile.exists()) {
    815             FileInputStream fin = null;
    816             DataInputStream in = null;
    817             try {
    818                 fin = new FileInputStream(mPasswordHashFile);
    819                 in = new DataInputStream(new BufferedInputStream(fin));
    820                 // integer length of the salt array, followed by the salt,
    821                 // then the hex pw hash string
    822                 int saltLen = in.readInt();
    823                 byte[] salt = new byte[saltLen];
    824                 in.readFully(salt);
    825                 mPasswordHash = in.readUTF();
    826                 mPasswordSalt = salt;
    827             } catch (IOException e) {
    828                 Slog.e(TAG, "Unable to read saved backup pw hash");
    829             } finally {
    830                 try {
    831                     if (in != null) in.close();
    832                     if (fin != null) fin.close();
    833                 } catch (IOException e) {
    834                     Slog.w(TAG, "Unable to close streams");
    835                 }
    836             }
    837         }
    838 
    839         // Alarm receivers for scheduled backups & initialization operations
    840         mRunBackupReceiver = new RunBackupReceiver();
    841         IntentFilter filter = new IntentFilter();
    842         filter.addAction(RUN_BACKUP_ACTION);
    843         context.registerReceiver(mRunBackupReceiver, filter,
    844                 android.Manifest.permission.BACKUP, null);
    845 
    846         mRunInitReceiver = new RunInitializeReceiver();
    847         filter = new IntentFilter();
    848         filter.addAction(RUN_INITIALIZE_ACTION);
    849         context.registerReceiver(mRunInitReceiver, filter,
    850                 android.Manifest.permission.BACKUP, null);
    851 
    852         Intent backupIntent = new Intent(RUN_BACKUP_ACTION);
    853         backupIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
    854         mRunBackupIntent = PendingIntent.getBroadcast(context, MSG_RUN_BACKUP, backupIntent, 0);
    855 
    856         Intent initIntent = new Intent(RUN_INITIALIZE_ACTION);
    857         backupIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
    858         mRunInitIntent = PendingIntent.getBroadcast(context, MSG_RUN_INITIALIZE, initIntent, 0);
    859 
    860         // Set up the backup-request journaling
    861         mJournalDir = new File(mBaseStateDir, "pending");
    862         mJournalDir.mkdirs();   // creates mBaseStateDir along the way
    863         mJournal = null;        // will be created on first use
    864 
    865         // Set up the various sorts of package tracking we do
    866         initPackageTracking();
    867 
    868         // Build our mapping of uid to backup client services.  This implicitly
    869         // schedules a backup pass on the Package Manager metadata the first
    870         // time anything needs to be backed up.
    871         synchronized (mBackupParticipants) {
    872             addPackageParticipantsLocked(null);
    873         }
    874 
    875         // Set up our transport options and initialize the default transport
    876         // TODO: Don't create transports that we don't need to?
    877         mCurrentTransport = Settings.Secure.getString(context.getContentResolver(),
    878                 Settings.Secure.BACKUP_TRANSPORT);
    879         if ("".equals(mCurrentTransport)) {
    880             mCurrentTransport = null;
    881         }
    882         if (DEBUG) Slog.v(TAG, "Starting with transport " + mCurrentTransport);
    883 
    884         // Find transport hosts and bind to their services
    885         Intent transportServiceIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST);
    886         List<ResolveInfo> hosts = mPackageManager.queryIntentServicesAsUser(
    887                 transportServiceIntent, 0, UserHandle.USER_OWNER);
    888         if (DEBUG) {
    889             Slog.v(TAG, "Found transports: " + ((hosts == null) ? "null" : hosts.size()));
    890         }
    891         if (hosts != null) {
    892             if (MORE_DEBUG) {
    893                 for (int i = 0; i < hosts.size(); i++) {
    894                     ServiceInfo info = hosts.get(i).serviceInfo;
    895                     Slog.v(TAG, "   " + info.packageName + "/" + info.name);
    896                 }
    897             }
    898             for (int i = 0; i < hosts.size(); i++) {
    899                 try {
    900                     ServiceInfo info = hosts.get(i).serviceInfo;
    901                     PackageInfo packInfo = mPackageManager.getPackageInfo(info.packageName, 0);
    902                     if ((packInfo.applicationInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
    903                         ComponentName svcName = new ComponentName(info.packageName, info.name);
    904                         if (DEBUG) {
    905                             Slog.i(TAG, "Binding to transport host " + svcName);
    906                         }
    907                         Intent intent = new Intent(transportServiceIntent);
    908                         intent.setComponent(svcName);
    909                         TransportConnection connection = new TransportConnection();
    910                         mTransportConnections.add(connection);
    911                         context.bindServiceAsUser(intent,
    912                                 connection, Context.BIND_AUTO_CREATE,
    913                                 UserHandle.OWNER);
    914                     } else {
    915                         Slog.w(TAG, "Transport package not privileged: " + info.packageName);
    916                     }
    917                 } catch (Exception e) {
    918                     Slog.e(TAG, "Problem resolving transport service: " + e.getMessage());
    919                 }
    920             }
    921         }
    922 
    923         // Now that we know about valid backup participants, parse any
    924         // leftover journal files into the pending backup set
    925         parseLeftoverJournals();
    926 
    927         // Power management
    928         mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*");
    929 
    930         // Start the backup passes going
    931         setBackupEnabled(areEnabled);
    932     }
    933 
    934     private class RunBackupReceiver extends BroadcastReceiver {
    935         public void onReceive(Context context, Intent intent) {
    936             if (RUN_BACKUP_ACTION.equals(intent.getAction())) {
    937                 synchronized (mQueueLock) {
    938                     if (mPendingInits.size() > 0) {
    939                         // If there are pending init operations, we process those
    940                         // and then settle into the usual periodic backup schedule.
    941                         if (DEBUG) Slog.v(TAG, "Init pending at scheduled backup");
    942                         try {
    943                             mAlarmManager.cancel(mRunInitIntent);
    944                             mRunInitIntent.send();
    945                         } catch (PendingIntent.CanceledException ce) {
    946                             Slog.e(TAG, "Run init intent cancelled");
    947                             // can't really do more than bail here
    948                         }
    949                     } else {
    950                         // Don't run backups now if we're disabled or not yet
    951                         // fully set up.
    952                         if (mEnabled && mProvisioned) {
    953                             if (!mBackupRunning) {
    954                                 if (DEBUG) Slog.v(TAG, "Running a backup pass");
    955 
    956                                 // Acquire the wakelock and pass it to the backup thread.  it will
    957                                 // be released once backup concludes.
    958                                 mBackupRunning = true;
    959                                 mWakelock.acquire();
    960 
    961                                 Message msg = mBackupHandler.obtainMessage(MSG_RUN_BACKUP);
    962                                 mBackupHandler.sendMessage(msg);
    963                             } else {
    964                                 Slog.i(TAG, "Backup time but one already running");
    965                             }
    966                         } else {
    967                             Slog.w(TAG, "Backup pass but e=" + mEnabled + " p=" + mProvisioned);
    968                         }
    969                     }
    970                 }
    971             }
    972         }
    973     }
    974 
    975     private class RunInitializeReceiver extends BroadcastReceiver {
    976         public void onReceive(Context context, Intent intent) {
    977             if (RUN_INITIALIZE_ACTION.equals(intent.getAction())) {
    978                 synchronized (mQueueLock) {
    979                     if (DEBUG) Slog.v(TAG, "Running a device init");
    980 
    981                     // Acquire the wakelock and pass it to the init thread.  it will
    982                     // be released once init concludes.
    983                     mWakelock.acquire();
    984 
    985                     Message msg = mBackupHandler.obtainMessage(MSG_RUN_INITIALIZE);
    986                     mBackupHandler.sendMessage(msg);
    987                 }
    988             }
    989         }
    990     }
    991 
    992     private void initPackageTracking() {
    993         if (DEBUG) Slog.v(TAG, "Initializing package tracking");
    994 
    995         // Remember our ancestral dataset
    996         mTokenFile = new File(mBaseStateDir, "ancestral");
    997         try {
    998             RandomAccessFile tf = new RandomAccessFile(mTokenFile, "r");
    999             int version = tf.readInt();
   1000             if (version == CURRENT_ANCESTRAL_RECORD_VERSION) {
   1001                 mAncestralToken = tf.readLong();
   1002                 mCurrentToken = tf.readLong();
   1003 
   1004                 int numPackages = tf.readInt();
   1005                 if (numPackages >= 0) {
   1006                     mAncestralPackages = new HashSet<String>();
   1007                     for (int i = 0; i < numPackages; i++) {
   1008                         String pkgName = tf.readUTF();
   1009                         mAncestralPackages.add(pkgName);
   1010                     }
   1011                 }
   1012             }
   1013             tf.close();
   1014         } catch (FileNotFoundException fnf) {
   1015             // Probably innocuous
   1016             Slog.v(TAG, "No ancestral data");
   1017         } catch (IOException e) {
   1018             Slog.w(TAG, "Unable to read token file", e);
   1019         }
   1020 
   1021         // Keep a log of what apps we've ever backed up.  Because we might have
   1022         // rebooted in the middle of an operation that was removing something from
   1023         // this log, we sanity-check its contents here and reconstruct it.
   1024         mEverStored = new File(mBaseStateDir, "processed");
   1025         File tempProcessedFile = new File(mBaseStateDir, "processed.new");
   1026 
   1027         // If we were in the middle of removing something from the ever-backed-up
   1028         // file, there might be a transient "processed.new" file still present.
   1029         // Ignore it -- we'll validate "processed" against the current package set.
   1030         if (tempProcessedFile.exists()) {
   1031             tempProcessedFile.delete();
   1032         }
   1033 
   1034         // If there are previous contents, parse them out then start a new
   1035         // file to continue the recordkeeping.
   1036         if (mEverStored.exists()) {
   1037             RandomAccessFile temp = null;
   1038             RandomAccessFile in = null;
   1039 
   1040             try {
   1041                 temp = new RandomAccessFile(tempProcessedFile, "rws");
   1042                 in = new RandomAccessFile(mEverStored, "r");
   1043 
   1044                 while (true) {
   1045                     PackageInfo info;
   1046                     String pkg = in.readUTF();
   1047                     try {
   1048                         info = mPackageManager.getPackageInfo(pkg, 0);
   1049                         mEverStoredApps.add(pkg);
   1050                         temp.writeUTF(pkg);
   1051                         if (MORE_DEBUG) Slog.v(TAG, "   + " + pkg);
   1052                     } catch (NameNotFoundException e) {
   1053                         // nope, this package was uninstalled; don't include it
   1054                         if (MORE_DEBUG) Slog.v(TAG, "   - " + pkg);
   1055                     }
   1056                 }
   1057             } catch (EOFException e) {
   1058                 // Once we've rewritten the backup history log, atomically replace the
   1059                 // old one with the new one then reopen the file for continuing use.
   1060                 if (!tempProcessedFile.renameTo(mEverStored)) {
   1061                     Slog.e(TAG, "Error renaming " + tempProcessedFile + " to " + mEverStored);
   1062                 }
   1063             } catch (IOException e) {
   1064                 Slog.e(TAG, "Error in processed file", e);
   1065             } finally {
   1066                 try { if (temp != null) temp.close(); } catch (IOException e) {}
   1067                 try { if (in != null) in.close(); } catch (IOException e) {}
   1068             }
   1069         }
   1070 
   1071         // Register for broadcasts about package install, etc., so we can
   1072         // update the provider list.
   1073         IntentFilter filter = new IntentFilter();
   1074         filter.addAction(Intent.ACTION_PACKAGE_ADDED);
   1075         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
   1076         filter.addDataScheme("package");
   1077         mContext.registerReceiver(mBroadcastReceiver, filter);
   1078         // Register for events related to sdcard installation.
   1079         IntentFilter sdFilter = new IntentFilter();
   1080         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
   1081         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
   1082         mContext.registerReceiver(mBroadcastReceiver, sdFilter);
   1083     }
   1084 
   1085     private void parseLeftoverJournals() {
   1086         for (File f : mJournalDir.listFiles()) {
   1087             if (mJournal == null || f.compareTo(mJournal) != 0) {
   1088                 // This isn't the current journal, so it must be a leftover.  Read
   1089                 // out the package names mentioned there and schedule them for
   1090                 // backup.
   1091                 RandomAccessFile in = null;
   1092                 try {
   1093                     Slog.i(TAG, "Found stale backup journal, scheduling");
   1094                     in = new RandomAccessFile(f, "r");
   1095                     while (true) {
   1096                         String packageName = in.readUTF();
   1097                         Slog.i(TAG, "  " + packageName);
   1098                         dataChangedImpl(packageName);
   1099                     }
   1100                 } catch (EOFException e) {
   1101                     // no more data; we're done
   1102                 } catch (Exception e) {
   1103                     Slog.e(TAG, "Can't read " + f, e);
   1104                 } finally {
   1105                     // close/delete the file
   1106                     try { if (in != null) in.close(); } catch (IOException e) {}
   1107                     f.delete();
   1108                 }
   1109             }
   1110         }
   1111     }
   1112 
   1113     private SecretKey buildPasswordKey(String pw, byte[] salt, int rounds) {
   1114         return buildCharArrayKey(pw.toCharArray(), salt, rounds);
   1115     }
   1116 
   1117     private SecretKey buildCharArrayKey(char[] pwArray, byte[] salt, int rounds) {
   1118         try {
   1119             SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
   1120             KeySpec ks = new PBEKeySpec(pwArray, salt, rounds, PBKDF2_KEY_SIZE);
   1121             return keyFactory.generateSecret(ks);
   1122         } catch (InvalidKeySpecException e) {
   1123             Slog.e(TAG, "Invalid key spec for PBKDF2!");
   1124         } catch (NoSuchAlgorithmException e) {
   1125             Slog.e(TAG, "PBKDF2 unavailable!");
   1126         }
   1127         return null;
   1128     }
   1129 
   1130     private String buildPasswordHash(String pw, byte[] salt, int rounds) {
   1131         SecretKey key = buildPasswordKey(pw, salt, rounds);
   1132         if (key != null) {
   1133             return byteArrayToHex(key.getEncoded());
   1134         }
   1135         return null;
   1136     }
   1137 
   1138     private String byteArrayToHex(byte[] data) {
   1139         StringBuilder buf = new StringBuilder(data.length * 2);
   1140         for (int i = 0; i < data.length; i++) {
   1141             buf.append(Byte.toHexString(data[i], true));
   1142         }
   1143         return buf.toString();
   1144     }
   1145 
   1146     private byte[] hexToByteArray(String digits) {
   1147         final int bytes = digits.length() / 2;
   1148         if (2*bytes != digits.length()) {
   1149             throw new IllegalArgumentException("Hex string must have an even number of digits");
   1150         }
   1151 
   1152         byte[] result = new byte[bytes];
   1153         for (int i = 0; i < digits.length(); i += 2) {
   1154             result[i/2] = (byte) Integer.parseInt(digits.substring(i, i+2), 16);
   1155         }
   1156         return result;
   1157     }
   1158 
   1159     private byte[] makeKeyChecksum(byte[] pwBytes, byte[] salt, int rounds) {
   1160         char[] mkAsChar = new char[pwBytes.length];
   1161         for (int i = 0; i < pwBytes.length; i++) {
   1162             mkAsChar[i] = (char) pwBytes[i];
   1163         }
   1164 
   1165         Key checksum = buildCharArrayKey(mkAsChar, salt, rounds);
   1166         return checksum.getEncoded();
   1167     }
   1168 
   1169     // Used for generating random salts or passwords
   1170     private byte[] randomBytes(int bits) {
   1171         byte[] array = new byte[bits / 8];
   1172         mRng.nextBytes(array);
   1173         return array;
   1174     }
   1175 
   1176     // Backup password management
   1177     boolean passwordMatchesSaved(String candidatePw, int rounds) {
   1178         // First, on an encrypted device we require matching the device pw
   1179         final boolean isEncrypted;
   1180         try {
   1181             isEncrypted = (mMountService.getEncryptionState() != MountService.ENCRYPTION_STATE_NONE);
   1182             if (isEncrypted) {
   1183                 if (DEBUG) {
   1184                     Slog.i(TAG, "Device encrypted; verifying against device data pw");
   1185                 }
   1186                 // 0 means the password validated
   1187                 // -2 means device not encrypted
   1188                 // Any other result is either password failure or an error condition,
   1189                 // so we refuse the match
   1190                 final int result = mMountService.verifyEncryptionPassword(candidatePw);
   1191                 if (result == 0) {
   1192                     if (MORE_DEBUG) Slog.d(TAG, "Pw verifies");
   1193                     return true;
   1194                 } else if (result != -2) {
   1195                     if (MORE_DEBUG) Slog.d(TAG, "Pw mismatch");
   1196                     return false;
   1197                 } else {
   1198                     // ...else the device is supposedly not encrypted.  HOWEVER, the
   1199                     // query about the encryption state said that the device *is*
   1200                     // encrypted, so ... we may have a problem.  Log it and refuse
   1201                     // the backup.
   1202                     Slog.e(TAG, "verified encryption state mismatch against query; no match allowed");
   1203                     return false;
   1204                 }
   1205             }
   1206         } catch (Exception e) {
   1207             // Something went wrong talking to the mount service.  This is very bad;
   1208             // assume that we fail password validation.
   1209             return false;
   1210         }
   1211 
   1212         if (mPasswordHash == null) {
   1213             // no current password case -- require that 'currentPw' be null or empty
   1214             if (candidatePw == null || "".equals(candidatePw)) {
   1215                 return true;
   1216             } // else the non-empty candidate does not match the empty stored pw
   1217         } else {
   1218             // hash the stated current pw and compare to the stored one
   1219             if (candidatePw != null && candidatePw.length() > 0) {
   1220                 String currentPwHash = buildPasswordHash(candidatePw, mPasswordSalt, rounds);
   1221                 if (mPasswordHash.equalsIgnoreCase(currentPwHash)) {
   1222                     // candidate hash matches the stored hash -- the password matches
   1223                     return true;
   1224                 }
   1225             } // else the stored pw is nonempty but the candidate is empty; no match
   1226         }
   1227         return false;
   1228     }
   1229 
   1230     @Override
   1231     public boolean setBackupPassword(String currentPw, String newPw) {
   1232         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   1233                 "setBackupPassword");
   1234 
   1235         // If the supplied pw doesn't hash to the the saved one, fail
   1236         if (!passwordMatchesSaved(currentPw, PBKDF2_HASH_ROUNDS)) {
   1237             return false;
   1238         }
   1239 
   1240         // Clearing the password is okay
   1241         if (newPw == null || newPw.isEmpty()) {
   1242             if (mPasswordHashFile.exists()) {
   1243                 if (!mPasswordHashFile.delete()) {
   1244                     // Unable to delete the old pw file, so fail
   1245                     Slog.e(TAG, "Unable to clear backup password");
   1246                     return false;
   1247                 }
   1248             }
   1249             mPasswordHash = null;
   1250             mPasswordSalt = null;
   1251             return true;
   1252         }
   1253 
   1254         try {
   1255             // Okay, build the hash of the new backup password
   1256             byte[] salt = randomBytes(PBKDF2_SALT_SIZE);
   1257             String newPwHash = buildPasswordHash(newPw, salt, PBKDF2_HASH_ROUNDS);
   1258 
   1259             OutputStream pwf = null, buffer = null;
   1260             DataOutputStream out = null;
   1261             try {
   1262                 pwf = new FileOutputStream(mPasswordHashFile);
   1263                 buffer = new BufferedOutputStream(pwf);
   1264                 out = new DataOutputStream(buffer);
   1265                 // integer length of the salt array, followed by the salt,
   1266                 // then the hex pw hash string
   1267                 out.writeInt(salt.length);
   1268                 out.write(salt);
   1269                 out.writeUTF(newPwHash);
   1270                 out.flush();
   1271                 mPasswordHash = newPwHash;
   1272                 mPasswordSalt = salt;
   1273                 return true;
   1274             } finally {
   1275                 if (out != null) out.close();
   1276                 if (buffer != null) buffer.close();
   1277                 if (pwf != null) pwf.close();
   1278             }
   1279         } catch (IOException e) {
   1280             Slog.e(TAG, "Unable to set backup password");
   1281         }
   1282         return false;
   1283     }
   1284 
   1285     @Override
   1286     public boolean hasBackupPassword() {
   1287         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   1288                 "hasBackupPassword");
   1289 
   1290         try {
   1291             return (mMountService.getEncryptionState() != IMountService.ENCRYPTION_STATE_NONE)
   1292                 || (mPasswordHash != null && mPasswordHash.length() > 0);
   1293         } catch (Exception e) {
   1294             // If we can't talk to the mount service we have a serious problem; fail
   1295             // "secure" i.e. assuming that we require a password
   1296             return true;
   1297         }
   1298     }
   1299 
   1300     // Maintain persistent state around whether need to do an initialize operation.
   1301     // Must be called with the queue lock held.
   1302     void recordInitPendingLocked(boolean isPending, String transportName) {
   1303         if (DEBUG) Slog.i(TAG, "recordInitPendingLocked: " + isPending
   1304                 + " on transport " + transportName);
   1305         mBackupHandler.removeMessages(MSG_RETRY_INIT);
   1306 
   1307         try {
   1308             IBackupTransport transport = getTransport(transportName);
   1309             if (transport != null) {
   1310                 String transportDirName = transport.transportDirName();
   1311                 File stateDir = new File(mBaseStateDir, transportDirName);
   1312                 File initPendingFile = new File(stateDir, INIT_SENTINEL_FILE_NAME);
   1313 
   1314                 if (isPending) {
   1315                     // We need an init before we can proceed with sending backup data.
   1316                     // Record that with an entry in our set of pending inits, as well as
   1317                     // journaling it via creation of a sentinel file.
   1318                     mPendingInits.add(transportName);
   1319                     try {
   1320                         (new FileOutputStream(initPendingFile)).close();
   1321                     } catch (IOException ioe) {
   1322                         // Something is badly wrong with our permissions; just try to move on
   1323                     }
   1324                 } else {
   1325                     // No more initialization needed; wipe the journal and reset our state.
   1326                     initPendingFile.delete();
   1327                     mPendingInits.remove(transportName);
   1328                 }
   1329                 return; // done; don't fall through to the error case
   1330             }
   1331         } catch (RemoteException e) {
   1332             // transport threw when asked its name; fall through to the lookup-failed case
   1333         }
   1334 
   1335         // The named transport doesn't exist or threw.  This operation is
   1336         // important, so we record the need for a an init and post a message
   1337         // to retry the init later.
   1338         if (isPending) {
   1339             mPendingInits.add(transportName);
   1340             mBackupHandler.sendMessageDelayed(
   1341                     mBackupHandler.obtainMessage(MSG_RETRY_INIT,
   1342                             (isPending ? 1 : 0),
   1343                             0,
   1344                             transportName),
   1345                     TRANSPORT_RETRY_INTERVAL);
   1346         }
   1347     }
   1348 
   1349     // Reset all of our bookkeeping, in response to having been told that
   1350     // the backend data has been wiped [due to idle expiry, for example],
   1351     // so we must re-upload all saved settings.
   1352     void resetBackupState(File stateFileDir) {
   1353         synchronized (mQueueLock) {
   1354             // Wipe the "what we've ever backed up" tracking
   1355             mEverStoredApps.clear();
   1356             mEverStored.delete();
   1357 
   1358             mCurrentToken = 0;
   1359             writeRestoreTokens();
   1360 
   1361             // Remove all the state files
   1362             for (File sf : stateFileDir.listFiles()) {
   1363                 // ... but don't touch the needs-init sentinel
   1364                 if (!sf.getName().equals(INIT_SENTINEL_FILE_NAME)) {
   1365                     sf.delete();
   1366                 }
   1367             }
   1368         }
   1369 
   1370         // Enqueue a new backup of every participant
   1371         synchronized (mBackupParticipants) {
   1372             final int N = mBackupParticipants.size();
   1373             for (int i=0; i<N; i++) {
   1374                 HashSet<String> participants = mBackupParticipants.valueAt(i);
   1375                 if (participants != null) {
   1376                     for (String packageName : participants) {
   1377                         dataChangedImpl(packageName);
   1378                     }
   1379                 }
   1380             }
   1381         }
   1382     }
   1383 
   1384     // Add a transport to our set of available backends.  If 'transport' is null, this
   1385     // is an unregistration, and the transport's entry is removed from our bookkeeping.
   1386     private void registerTransport(String name, String component, IBackupTransport transport) {
   1387         synchronized (mTransports) {
   1388             if (DEBUG) Slog.v(TAG, "Registering transport "
   1389                     + component + "::" + name + " = " + transport);
   1390             if (transport != null) {
   1391                 mTransports.put(name, transport);
   1392                 mTransportNames.put(component, name);
   1393             } else {
   1394                 mTransports.remove(mTransportNames.get(component));
   1395                 mTransportNames.remove(component);
   1396                 // Nothing further to do in the unregistration case
   1397                 return;
   1398             }
   1399         }
   1400 
   1401         // If the init sentinel file exists, we need to be sure to perform the init
   1402         // as soon as practical.  We also create the state directory at registration
   1403         // time to ensure it's present from the outset.
   1404         try {
   1405             String transportName = transport.transportDirName();
   1406             File stateDir = new File(mBaseStateDir, transportName);
   1407             stateDir.mkdirs();
   1408 
   1409             File initSentinel = new File(stateDir, INIT_SENTINEL_FILE_NAME);
   1410             if (initSentinel.exists()) {
   1411                 synchronized (mQueueLock) {
   1412                     mPendingInits.add(transportName);
   1413 
   1414                     // TODO: pick a better starting time than now + 1 minute
   1415                     long delay = 1000 * 60; // one minute, in milliseconds
   1416                     mAlarmManager.set(AlarmManager.RTC_WAKEUP,
   1417                             System.currentTimeMillis() + delay, mRunInitIntent);
   1418                 }
   1419             }
   1420         } catch (RemoteException e) {
   1421             // the transport threw when asked its file naming prefs; declare it invalid
   1422             Slog.e(TAG, "Unable to register transport as " + name);
   1423             mTransportNames.remove(component);
   1424             mTransports.remove(name);
   1425         }
   1426     }
   1427 
   1428     // ----- Track installation/removal of packages -----
   1429     BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
   1430         public void onReceive(Context context, Intent intent) {
   1431             if (DEBUG) Slog.d(TAG, "Received broadcast " + intent);
   1432 
   1433             String action = intent.getAction();
   1434             boolean replacing = false;
   1435             boolean added = false;
   1436             Bundle extras = intent.getExtras();
   1437             String pkgList[] = null;
   1438             if (Intent.ACTION_PACKAGE_ADDED.equals(action) ||
   1439                     Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
   1440                 Uri uri = intent.getData();
   1441                 if (uri == null) {
   1442                     return;
   1443                 }
   1444                 String pkgName = uri.getSchemeSpecificPart();
   1445                 if (pkgName != null) {
   1446                     pkgList = new String[] { pkgName };
   1447                 }
   1448                 added = Intent.ACTION_PACKAGE_ADDED.equals(action);
   1449                 replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false);
   1450             } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
   1451                 added = true;
   1452                 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
   1453             } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
   1454                 added = false;
   1455                 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
   1456             }
   1457 
   1458             if (pkgList == null || pkgList.length == 0) {
   1459                 return;
   1460             }
   1461 
   1462             final int uid = extras.getInt(Intent.EXTRA_UID);
   1463             if (added) {
   1464                 synchronized (mBackupParticipants) {
   1465                     if (replacing) {
   1466                         // This is the package-replaced case; we just remove the entry
   1467                         // under the old uid and fall through to re-add.
   1468                         removePackageParticipantsLocked(pkgList, uid);
   1469                     }
   1470                     addPackageParticipantsLocked(pkgList);
   1471                 }
   1472             } else {
   1473                 if (replacing) {
   1474                     // The package is being updated.  We'll receive a PACKAGE_ADDED shortly.
   1475                 } else {
   1476                     synchronized (mBackupParticipants) {
   1477                         removePackageParticipantsLocked(pkgList, uid);
   1478                     }
   1479                 }
   1480             }
   1481         }
   1482     };
   1483 
   1484     // ----- Track connection to transports service -----
   1485     class TransportConnection implements ServiceConnection {
   1486         @Override
   1487         public void onServiceConnected(ComponentName component, IBinder service) {
   1488             if (DEBUG) Slog.v(TAG, "Connected to transport " + component);
   1489             try {
   1490                 IBackupTransport transport = IBackupTransport.Stub.asInterface(service);
   1491                 registerTransport(transport.name(), component.flattenToShortString(), transport);
   1492             } catch (RemoteException e) {
   1493                 Slog.e(TAG, "Unable to register transport " + component);
   1494             }
   1495         }
   1496 
   1497         @Override
   1498         public void onServiceDisconnected(ComponentName component) {
   1499             if (DEBUG) Slog.v(TAG, "Disconnected from transport " + component);
   1500             registerTransport(null, component.flattenToShortString(), null);
   1501         }
   1502     };
   1503 
   1504     // Add the backup agents in the given packages to our set of known backup participants.
   1505     // If 'packageNames' is null, adds all backup agents in the whole system.
   1506     void addPackageParticipantsLocked(String[] packageNames) {
   1507         // Look for apps that define the android:backupAgent attribute
   1508         List<PackageInfo> targetApps = allAgentPackages();
   1509         if (packageNames != null) {
   1510             if (DEBUG) Slog.v(TAG, "addPackageParticipantsLocked: #" + packageNames.length);
   1511             for (String packageName : packageNames) {
   1512                 addPackageParticipantsLockedInner(packageName, targetApps);
   1513             }
   1514         } else {
   1515             if (DEBUG) Slog.v(TAG, "addPackageParticipantsLocked: all");
   1516             addPackageParticipantsLockedInner(null, targetApps);
   1517         }
   1518     }
   1519 
   1520     private void addPackageParticipantsLockedInner(String packageName,
   1521             List<PackageInfo> targetPkgs) {
   1522         if (MORE_DEBUG) {
   1523             Slog.v(TAG, "Examining " + packageName + " for backup agent");
   1524         }
   1525 
   1526         for (PackageInfo pkg : targetPkgs) {
   1527             if (packageName == null || pkg.packageName.equals(packageName)) {
   1528                 int uid = pkg.applicationInfo.uid;
   1529                 HashSet<String> set = mBackupParticipants.get(uid);
   1530                 if (set == null) {
   1531                     set = new HashSet<String>();
   1532                     mBackupParticipants.put(uid, set);
   1533                 }
   1534                 set.add(pkg.packageName);
   1535                 if (MORE_DEBUG) Slog.v(TAG, "Agent found; added");
   1536 
   1537                 // Schedule a backup for it on general principles
   1538                 if (DEBUG) Slog.i(TAG, "Scheduling backup for new app " + pkg.packageName);
   1539                 dataChangedImpl(pkg.packageName);
   1540             }
   1541         }
   1542     }
   1543 
   1544     // Remove the given packages' entries from our known active set.
   1545     void removePackageParticipantsLocked(String[] packageNames, int oldUid) {
   1546         if (packageNames == null) {
   1547             Slog.w(TAG, "removePackageParticipants with null list");
   1548             return;
   1549         }
   1550 
   1551         if (DEBUG) Slog.v(TAG, "removePackageParticipantsLocked: uid=" + oldUid
   1552                 + " #" + packageNames.length);
   1553         for (String pkg : packageNames) {
   1554             // Known previous UID, so we know which package set to check
   1555             HashSet<String> set = mBackupParticipants.get(oldUid);
   1556             if (set != null && set.contains(pkg)) {
   1557                 removePackageFromSetLocked(set, pkg);
   1558                 if (set.isEmpty()) {
   1559                     if (MORE_DEBUG) Slog.v(TAG, "  last one of this uid; purging set");
   1560                     mBackupParticipants.remove(oldUid);
   1561                 }
   1562             }
   1563         }
   1564     }
   1565 
   1566     private void removePackageFromSetLocked(final HashSet<String> set,
   1567             final String packageName) {
   1568         if (set.contains(packageName)) {
   1569             // Found it.  Remove this one package from the bookkeeping, and
   1570             // if it's the last participating app under this uid we drop the
   1571             // (now-empty) set as well.
   1572             // Note that we deliberately leave it 'known' in the "ever backed up"
   1573             // bookkeeping so that its current-dataset data will be retrieved
   1574             // if the app is subsequently reinstalled
   1575             if (MORE_DEBUG) Slog.v(TAG, "  removing participant " + packageName);
   1576             set.remove(packageName);
   1577             mPendingBackups.remove(packageName);
   1578         }
   1579     }
   1580 
   1581     // Returns the set of all applications that define an android:backupAgent attribute
   1582     List<PackageInfo> allAgentPackages() {
   1583         // !!! TODO: cache this and regenerate only when necessary
   1584         int flags = PackageManager.GET_SIGNATURES;
   1585         List<PackageInfo> packages = mPackageManager.getInstalledPackages(flags);
   1586         int N = packages.size();
   1587         for (int a = N-1; a >= 0; a--) {
   1588             PackageInfo pkg = packages.get(a);
   1589             try {
   1590                 ApplicationInfo app = pkg.applicationInfo;
   1591                 if (((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0)
   1592                         || app.backupAgentName == null) {
   1593                     packages.remove(a);
   1594                 }
   1595                 else {
   1596                     // we will need the shared library path, so look that up and store it here
   1597                     app = mPackageManager.getApplicationInfo(pkg.packageName,
   1598                             PackageManager.GET_SHARED_LIBRARY_FILES);
   1599                     pkg.applicationInfo.sharedLibraryFiles = app.sharedLibraryFiles;
   1600                 }
   1601             } catch (NameNotFoundException e) {
   1602                 packages.remove(a);
   1603             }
   1604         }
   1605         return packages;
   1606     }
   1607 
   1608     // Called from the backup task: record that the given app has been successfully
   1609     // backed up at least once
   1610     void logBackupComplete(String packageName) {
   1611         if (packageName.equals(PACKAGE_MANAGER_SENTINEL)) return;
   1612 
   1613         synchronized (mEverStoredApps) {
   1614             if (!mEverStoredApps.add(packageName)) return;
   1615 
   1616             RandomAccessFile out = null;
   1617             try {
   1618                 out = new RandomAccessFile(mEverStored, "rws");
   1619                 out.seek(out.length());
   1620                 out.writeUTF(packageName);
   1621             } catch (IOException e) {
   1622                 Slog.e(TAG, "Can't log backup of " + packageName + " to " + mEverStored);
   1623             } finally {
   1624                 try { if (out != null) out.close(); } catch (IOException e) {}
   1625             }
   1626         }
   1627     }
   1628 
   1629     // Remove our awareness of having ever backed up the given package
   1630     void removeEverBackedUp(String packageName) {
   1631         if (DEBUG) Slog.v(TAG, "Removing backed-up knowledge of " + packageName);
   1632         if (MORE_DEBUG) Slog.v(TAG, "New set:");
   1633 
   1634         synchronized (mEverStoredApps) {
   1635             // Rewrite the file and rename to overwrite.  If we reboot in the middle,
   1636             // we'll recognize on initialization time that the package no longer
   1637             // exists and fix it up then.
   1638             File tempKnownFile = new File(mBaseStateDir, "processed.new");
   1639             RandomAccessFile known = null;
   1640             try {
   1641                 known = new RandomAccessFile(tempKnownFile, "rws");
   1642                 mEverStoredApps.remove(packageName);
   1643                 for (String s : mEverStoredApps) {
   1644                     known.writeUTF(s);
   1645                     if (MORE_DEBUG) Slog.v(TAG, "    " + s);
   1646                 }
   1647                 known.close();
   1648                 known = null;
   1649                 if (!tempKnownFile.renameTo(mEverStored)) {
   1650                     throw new IOException("Can't rename " + tempKnownFile + " to " + mEverStored);
   1651                 }
   1652             } catch (IOException e) {
   1653                 // Bad: we couldn't create the new copy.  For safety's sake we
   1654                 // abandon the whole process and remove all what's-backed-up
   1655                 // state entirely, meaning we'll force a backup pass for every
   1656                 // participant on the next boot or [re]install.
   1657                 Slog.w(TAG, "Error rewriting " + mEverStored, e);
   1658                 mEverStoredApps.clear();
   1659                 tempKnownFile.delete();
   1660                 mEverStored.delete();
   1661             } finally {
   1662                 try { if (known != null) known.close(); } catch (IOException e) {}
   1663             }
   1664         }
   1665     }
   1666 
   1667     // Persistently record the current and ancestral backup tokens as well
   1668     // as the set of packages with data [supposedly] available in the
   1669     // ancestral dataset.
   1670     void writeRestoreTokens() {
   1671         try {
   1672             RandomAccessFile af = new RandomAccessFile(mTokenFile, "rwd");
   1673 
   1674             // First, the version number of this record, for futureproofing
   1675             af.writeInt(CURRENT_ANCESTRAL_RECORD_VERSION);
   1676 
   1677             // Write the ancestral and current tokens
   1678             af.writeLong(mAncestralToken);
   1679             af.writeLong(mCurrentToken);
   1680 
   1681             // Now write the set of ancestral packages
   1682             if (mAncestralPackages == null) {
   1683                 af.writeInt(-1);
   1684             } else {
   1685                 af.writeInt(mAncestralPackages.size());
   1686                 if (DEBUG) Slog.v(TAG, "Ancestral packages:  " + mAncestralPackages.size());
   1687                 for (String pkgName : mAncestralPackages) {
   1688                     af.writeUTF(pkgName);
   1689                     if (MORE_DEBUG) Slog.v(TAG, "   " + pkgName);
   1690                 }
   1691             }
   1692             af.close();
   1693         } catch (IOException e) {
   1694             Slog.w(TAG, "Unable to write token file:", e);
   1695         }
   1696     }
   1697 
   1698     // Return the given transport
   1699     private IBackupTransport getTransport(String transportName) {
   1700         synchronized (mTransports) {
   1701             IBackupTransport transport = mTransports.get(transportName);
   1702             if (transport == null) {
   1703                 Slog.w(TAG, "Requested unavailable transport: " + transportName);
   1704             }
   1705             return transport;
   1706         }
   1707     }
   1708 
   1709     // fire off a backup agent, blocking until it attaches or times out
   1710     IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode) {
   1711         IBackupAgent agent = null;
   1712         synchronized(mAgentConnectLock) {
   1713             mConnecting = true;
   1714             mConnectedAgent = null;
   1715             try {
   1716                 if (mActivityManager.bindBackupAgent(app, mode)) {
   1717                     Slog.d(TAG, "awaiting agent for " + app);
   1718 
   1719                     // success; wait for the agent to arrive
   1720                     // only wait 10 seconds for the bind to happen
   1721                     long timeoutMark = System.currentTimeMillis() + TIMEOUT_INTERVAL;
   1722                     while (mConnecting && mConnectedAgent == null
   1723                             && (System.currentTimeMillis() < timeoutMark)) {
   1724                         try {
   1725                             mAgentConnectLock.wait(5000);
   1726                         } catch (InterruptedException e) {
   1727                             // just bail
   1728                             if (DEBUG) Slog.w(TAG, "Interrupted: " + e);
   1729                             mActivityManager.clearPendingBackup();
   1730                             return null;
   1731                         }
   1732                     }
   1733 
   1734                     // if we timed out with no connect, abort and move on
   1735                     if (mConnecting == true) {
   1736                         Slog.w(TAG, "Timeout waiting for agent " + app);
   1737                         mActivityManager.clearPendingBackup();
   1738                         return null;
   1739                     }
   1740                     if (DEBUG) Slog.i(TAG, "got agent " + mConnectedAgent);
   1741                     agent = mConnectedAgent;
   1742                 }
   1743             } catch (RemoteException e) {
   1744                 // can't happen - ActivityManager is local
   1745             }
   1746         }
   1747         return agent;
   1748     }
   1749 
   1750     // clear an application's data, blocking until the operation completes or times out
   1751     void clearApplicationDataSynchronous(String packageName) {
   1752         // Don't wipe packages marked allowClearUserData=false
   1753         try {
   1754             PackageInfo info = mPackageManager.getPackageInfo(packageName, 0);
   1755             if ((info.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA) == 0) {
   1756                 if (MORE_DEBUG) Slog.i(TAG, "allowClearUserData=false so not wiping "
   1757                         + packageName);
   1758                 return;
   1759             }
   1760         } catch (NameNotFoundException e) {
   1761             Slog.w(TAG, "Tried to clear data for " + packageName + " but not found");
   1762             return;
   1763         }
   1764 
   1765         ClearDataObserver observer = new ClearDataObserver();
   1766 
   1767         synchronized(mClearDataLock) {
   1768             mClearingData = true;
   1769             try {
   1770                 mActivityManager.clearApplicationUserData(packageName, observer, 0);
   1771             } catch (RemoteException e) {
   1772                 // can't happen because the activity manager is in this process
   1773             }
   1774 
   1775             // only wait 10 seconds for the clear data to happen
   1776             long timeoutMark = System.currentTimeMillis() + TIMEOUT_INTERVAL;
   1777             while (mClearingData && (System.currentTimeMillis() < timeoutMark)) {
   1778                 try {
   1779                     mClearDataLock.wait(5000);
   1780                 } catch (InterruptedException e) {
   1781                     // won't happen, but still.
   1782                     mClearingData = false;
   1783                 }
   1784             }
   1785         }
   1786     }
   1787 
   1788     class ClearDataObserver extends IPackageDataObserver.Stub {
   1789         public void onRemoveCompleted(String packageName, boolean succeeded) {
   1790             synchronized(mClearDataLock) {
   1791                 mClearingData = false;
   1792                 mClearDataLock.notifyAll();
   1793             }
   1794         }
   1795     }
   1796 
   1797     // Get the restore-set token for the best-available restore set for this package:
   1798     // the active set if possible, else the ancestral one.  Returns zero if none available.
   1799     long getAvailableRestoreToken(String packageName) {
   1800         long token = mAncestralToken;
   1801         synchronized (mQueueLock) {
   1802             if (mEverStoredApps.contains(packageName)) {
   1803                 token = mCurrentToken;
   1804             }
   1805         }
   1806         return token;
   1807     }
   1808 
   1809     // -----
   1810     // Interface and methods used by the asynchronous-with-timeout backup/restore operations
   1811 
   1812     interface BackupRestoreTask {
   1813         // Execute one tick of whatever state machine the task implements
   1814         void execute();
   1815 
   1816         // An operation that wanted a callback has completed
   1817         void operationComplete();
   1818 
   1819         // An operation that wanted a callback has timed out
   1820         void handleTimeout();
   1821     }
   1822 
   1823     void prepareOperationTimeout(int token, long interval, BackupRestoreTask callback) {
   1824         if (MORE_DEBUG) Slog.v(TAG, "starting timeout: token=" + Integer.toHexString(token)
   1825                 + " interval=" + interval);
   1826         synchronized (mCurrentOpLock) {
   1827             mCurrentOperations.put(token, new Operation(OP_PENDING, callback));
   1828 
   1829             Message msg = mBackupHandler.obtainMessage(MSG_TIMEOUT, token, 0, callback);
   1830             mBackupHandler.sendMessageDelayed(msg, interval);
   1831         }
   1832     }
   1833 
   1834     // synchronous waiter case
   1835     boolean waitUntilOperationComplete(int token) {
   1836         if (MORE_DEBUG) Slog.i(TAG, "Blocking until operation complete for "
   1837                 + Integer.toHexString(token));
   1838         int finalState = OP_PENDING;
   1839         Operation op = null;
   1840         synchronized (mCurrentOpLock) {
   1841             while (true) {
   1842                 op = mCurrentOperations.get(token);
   1843                 if (op == null) {
   1844                     // mysterious disappearance: treat as success with no callback
   1845                     break;
   1846                 } else {
   1847                     if (op.state == OP_PENDING) {
   1848                         try {
   1849                             mCurrentOpLock.wait();
   1850                         } catch (InterruptedException e) {}
   1851                         // When the wait is notified we loop around and recheck the current state
   1852                     } else {
   1853                         // No longer pending; we're done
   1854                         finalState = op.state;
   1855                         break;
   1856                     }
   1857                 }
   1858             }
   1859         }
   1860 
   1861         mBackupHandler.removeMessages(MSG_TIMEOUT);
   1862         if (MORE_DEBUG) Slog.v(TAG, "operation " + Integer.toHexString(token)
   1863                 + " complete: finalState=" + finalState);
   1864         return finalState == OP_ACKNOWLEDGED;
   1865     }
   1866 
   1867     void handleTimeout(int token, Object obj) {
   1868         // Notify any synchronous waiters
   1869         Operation op = null;
   1870         synchronized (mCurrentOpLock) {
   1871             op = mCurrentOperations.get(token);
   1872             if (MORE_DEBUG) {
   1873                 if (op == null) Slog.w(TAG, "Timeout of token " + Integer.toHexString(token)
   1874                         + " but no op found");
   1875             }
   1876             int state = (op != null) ? op.state : OP_TIMEOUT;
   1877             if (state == OP_PENDING) {
   1878                 if (DEBUG) Slog.v(TAG, "TIMEOUT: token=" + Integer.toHexString(token));
   1879                 op.state = OP_TIMEOUT;
   1880                 mCurrentOperations.put(token, op);
   1881             }
   1882             mCurrentOpLock.notifyAll();
   1883         }
   1884 
   1885         // If there's a TimeoutHandler for this event, call it
   1886         if (op != null && op.callback != null) {
   1887             op.callback.handleTimeout();
   1888         }
   1889     }
   1890 
   1891     // ----- Back up a set of applications via a worker thread -----
   1892 
   1893     enum BackupState {
   1894         INITIAL,
   1895         RUNNING_QUEUE,
   1896         FINAL
   1897     }
   1898 
   1899     class PerformBackupTask implements BackupRestoreTask {
   1900         private static final String TAG = "PerformBackupTask";
   1901 
   1902         IBackupTransport mTransport;
   1903         ArrayList<BackupRequest> mQueue;
   1904         ArrayList<BackupRequest> mOriginalQueue;
   1905         File mStateDir;
   1906         File mJournal;
   1907         BackupState mCurrentState;
   1908 
   1909         // carried information about the current in-flight operation
   1910         PackageInfo mCurrentPackage;
   1911         File mSavedStateName;
   1912         File mBackupDataName;
   1913         File mNewStateName;
   1914         ParcelFileDescriptor mSavedState;
   1915         ParcelFileDescriptor mBackupData;
   1916         ParcelFileDescriptor mNewState;
   1917         int mStatus;
   1918         boolean mFinished;
   1919 
   1920         public PerformBackupTask(IBackupTransport transport, String dirName,
   1921                 ArrayList<BackupRequest> queue, File journal) {
   1922             mTransport = transport;
   1923             mOriginalQueue = queue;
   1924             mJournal = journal;
   1925 
   1926             mStateDir = new File(mBaseStateDir, dirName);
   1927 
   1928             mCurrentState = BackupState.INITIAL;
   1929             mFinished = false;
   1930 
   1931             addBackupTrace("STATE => INITIAL");
   1932         }
   1933 
   1934         // Main entry point: perform one chunk of work, updating the state as appropriate
   1935         // and reposting the next chunk to the primary backup handler thread.
   1936         @Override
   1937         public void execute() {
   1938             switch (mCurrentState) {
   1939                 case INITIAL:
   1940                     beginBackup();
   1941                     break;
   1942 
   1943                 case RUNNING_QUEUE:
   1944                     invokeNextAgent();
   1945                     break;
   1946 
   1947                 case FINAL:
   1948                     if (!mFinished) finalizeBackup();
   1949                     else {
   1950                         Slog.e(TAG, "Duplicate finish");
   1951                     }
   1952                     mFinished = true;
   1953                     break;
   1954             }
   1955         }
   1956 
   1957         // We're starting a backup pass.  Initialize the transport and send
   1958         // the PM metadata blob if we haven't already.
   1959         void beginBackup() {
   1960             if (DEBUG_BACKUP_TRACE) {
   1961                 clearBackupTrace();
   1962                 StringBuilder b = new StringBuilder(256);
   1963                 b.append("beginBackup: [");
   1964                 for (BackupRequest req : mOriginalQueue) {
   1965                     b.append(' ');
   1966                     b.append(req.packageName);
   1967                 }
   1968                 b.append(" ]");
   1969                 addBackupTrace(b.toString());
   1970             }
   1971 
   1972             mStatus = BackupConstants.TRANSPORT_OK;
   1973 
   1974             // Sanity check: if the queue is empty we have no work to do.
   1975             if (mOriginalQueue.isEmpty()) {
   1976                 Slog.w(TAG, "Backup begun with an empty queue - nothing to do.");
   1977                 addBackupTrace("queue empty at begin");
   1978                 executeNextState(BackupState.FINAL);
   1979                 return;
   1980             }
   1981 
   1982             // We need to retain the original queue contents in case of transport
   1983             // failure, but we want a working copy that we can manipulate along
   1984             // the way.
   1985             mQueue = (ArrayList<BackupRequest>) mOriginalQueue.clone();
   1986 
   1987             if (DEBUG) Slog.v(TAG, "Beginning backup of " + mQueue.size() + " targets");
   1988 
   1989             File pmState = new File(mStateDir, PACKAGE_MANAGER_SENTINEL);
   1990             try {
   1991                 final String transportName = mTransport.transportDirName();
   1992                 EventLog.writeEvent(EventLogTags.BACKUP_START, transportName);
   1993 
   1994                 // If we haven't stored package manager metadata yet, we must init the transport.
   1995                 if (mStatus == BackupConstants.TRANSPORT_OK && pmState.length() <= 0) {
   1996                     Slog.i(TAG, "Initializing (wiping) backup state and transport storage");
   1997                     addBackupTrace("initializing transport " + transportName);
   1998                     resetBackupState(mStateDir);  // Just to make sure.
   1999                     mStatus = mTransport.initializeDevice();
   2000 
   2001                     addBackupTrace("transport.initializeDevice() == " + mStatus);
   2002                     if (mStatus == BackupConstants.TRANSPORT_OK) {
   2003                         EventLog.writeEvent(EventLogTags.BACKUP_INITIALIZE);
   2004                     } else {
   2005                         EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, "(initialize)");
   2006                         Slog.e(TAG, "Transport error in initializeDevice()");
   2007                     }
   2008                 }
   2009 
   2010                 // The package manager doesn't have a proper <application> etc, but since
   2011                 // it's running here in the system process we can just set up its agent
   2012                 // directly and use a synthetic BackupRequest.  We always run this pass
   2013                 // because it's cheap and this way we guarantee that we don't get out of
   2014                 // step even if we're selecting among various transports at run time.
   2015                 if (mStatus == BackupConstants.TRANSPORT_OK) {
   2016                     PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
   2017                             mPackageManager, allAgentPackages());
   2018                     mStatus = invokeAgentForBackup(PACKAGE_MANAGER_SENTINEL,
   2019                             IBackupAgent.Stub.asInterface(pmAgent.onBind()), mTransport);
   2020                     addBackupTrace("PMBA invoke: " + mStatus);
   2021                 }
   2022 
   2023                 if (mStatus == BackupConstants.TRANSPORT_NOT_INITIALIZED) {
   2024                     // The backend reports that our dataset has been wiped.  Note this in
   2025                     // the event log; the no-success code below will reset the backup
   2026                     // state as well.
   2027                     EventLog.writeEvent(EventLogTags.BACKUP_RESET, mTransport.transportDirName());
   2028                 }
   2029             } catch (Exception e) {
   2030                 Slog.e(TAG, "Error in backup thread", e);
   2031                 addBackupTrace("Exception in backup thread: " + e);
   2032                 mStatus = BackupConstants.TRANSPORT_ERROR;
   2033             } finally {
   2034                 // If we've succeeded so far, invokeAgentForBackup() will have run the PM
   2035                 // metadata and its completion/timeout callback will continue the state
   2036                 // machine chain.  If it failed that won't happen; we handle that now.
   2037                 addBackupTrace("exiting prelim: " + mStatus);
   2038                 if (mStatus != BackupConstants.TRANSPORT_OK) {
   2039                     // if things went wrong at this point, we need to
   2040                     // restage everything and try again later.
   2041                     resetBackupState(mStateDir);  // Just to make sure.
   2042                     executeNextState(BackupState.FINAL);
   2043                 }
   2044             }
   2045         }
   2046 
   2047         // Transport has been initialized and the PM metadata submitted successfully
   2048         // if that was warranted.  Now we process the single next thing in the queue.
   2049         void invokeNextAgent() {
   2050             mStatus = BackupConstants.TRANSPORT_OK;
   2051             addBackupTrace("invoke q=" + mQueue.size());
   2052 
   2053             // Sanity check that we have work to do.  If not, skip to the end where
   2054             // we reestablish the wakelock invariants etc.
   2055             if (mQueue.isEmpty()) {
   2056                 if (DEBUG) Slog.i(TAG, "queue now empty");
   2057                 executeNextState(BackupState.FINAL);
   2058                 return;
   2059             }
   2060 
   2061             // pop the entry we're going to process on this step
   2062             BackupRequest request = mQueue.get(0);
   2063             mQueue.remove(0);
   2064 
   2065             Slog.d(TAG, "starting agent for backup of " + request);
   2066             addBackupTrace("launch agent for " + request.packageName);
   2067 
   2068             // Verify that the requested app exists; it might be something that
   2069             // requested a backup but was then uninstalled.  The request was
   2070             // journalled and rather than tamper with the journal it's safer
   2071             // to sanity-check here.  This also gives us the classname of the
   2072             // package's backup agent.
   2073             try {
   2074                 mCurrentPackage = mPackageManager.getPackageInfo(request.packageName,
   2075                         PackageManager.GET_SIGNATURES);
   2076                 if (mCurrentPackage.applicationInfo.backupAgentName == null) {
   2077                     // The manifest has changed but we had a stale backup request pending.
   2078                     // This won't happen again because the app won't be requesting further
   2079                     // backups.
   2080                     Slog.i(TAG, "Package " + request.packageName
   2081                             + " no longer supports backup; skipping");
   2082                     addBackupTrace("skipping - no agent, completion is noop");
   2083                     executeNextState(BackupState.RUNNING_QUEUE);
   2084                     return;
   2085                 }
   2086 
   2087                 if ((mCurrentPackage.applicationInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0) {
   2088                     // The app has been force-stopped or cleared or just installed,
   2089                     // and not yet launched out of that state, so just as it won't
   2090                     // receive broadcasts, we won't run it for backup.
   2091                     addBackupTrace("skipping - stopped");
   2092                     executeNextState(BackupState.RUNNING_QUEUE);
   2093                     return;
   2094                 }
   2095 
   2096                 IBackupAgent agent = null;
   2097                 try {
   2098                     mWakelock.setWorkSource(new WorkSource(mCurrentPackage.applicationInfo.uid));
   2099                     agent = bindToAgentSynchronous(mCurrentPackage.applicationInfo,
   2100                             IApplicationThread.BACKUP_MODE_INCREMENTAL);
   2101                     addBackupTrace("agent bound; a? = " + (agent != null));
   2102                     if (agent != null) {
   2103                         mStatus = invokeAgentForBackup(request.packageName, agent, mTransport);
   2104                         // at this point we'll either get a completion callback from the
   2105                         // agent, or a timeout message on the main handler.  either way, we're
   2106                         // done here as long as we're successful so far.
   2107                     } else {
   2108                         // Timeout waiting for the agent
   2109                         mStatus = BackupConstants.AGENT_ERROR;
   2110                     }
   2111                 } catch (SecurityException ex) {
   2112                     // Try for the next one.
   2113                     Slog.d(TAG, "error in bind/backup", ex);
   2114                     mStatus = BackupConstants.AGENT_ERROR;
   2115                             addBackupTrace("agent SE");
   2116                 }
   2117             } catch (NameNotFoundException e) {
   2118                 Slog.d(TAG, "Package does not exist; skipping");
   2119                 addBackupTrace("no such package");
   2120                 mStatus = BackupConstants.AGENT_UNKNOWN;
   2121             } finally {
   2122                 mWakelock.setWorkSource(null);
   2123 
   2124                 // If there was an agent error, no timeout/completion handling will occur.
   2125                 // That means we need to direct to the next state ourselves.
   2126                 if (mStatus != BackupConstants.TRANSPORT_OK) {
   2127                     BackupState nextState = BackupState.RUNNING_QUEUE;
   2128 
   2129                     // An agent-level failure means we reenqueue this one agent for
   2130                     // a later retry, but otherwise proceed normally.
   2131                     if (mStatus == BackupConstants.AGENT_ERROR) {
   2132                         if (MORE_DEBUG) Slog.i(TAG, "Agent failure for " + request.packageName
   2133                                 + " - restaging");
   2134                         dataChangedImpl(request.packageName);
   2135                         mStatus = BackupConstants.TRANSPORT_OK;
   2136                         if (mQueue.isEmpty()) nextState = BackupState.FINAL;
   2137                     } else if (mStatus == BackupConstants.AGENT_UNKNOWN) {
   2138                         // Failed lookup of the app, so we couldn't bring up an agent, but
   2139                         // we're otherwise fine.  Just drop it and go on to the next as usual.
   2140                         mStatus = BackupConstants.TRANSPORT_OK;
   2141                     } else {
   2142                         // Transport-level failure means we reenqueue everything
   2143                         revertAndEndBackup();
   2144                         nextState = BackupState.FINAL;
   2145                     }
   2146 
   2147                     executeNextState(nextState);
   2148                 } else {
   2149                     addBackupTrace("expecting completion/timeout callback");
   2150                 }
   2151             }
   2152         }
   2153 
   2154         void finalizeBackup() {
   2155             addBackupTrace("finishing");
   2156 
   2157             // Either backup was successful, in which case we of course do not need
   2158             // this pass's journal any more; or it failed, in which case we just
   2159             // re-enqueued all of these packages in the current active journal.
   2160             // Either way, we no longer need this pass's journal.
   2161             if (mJournal != null && !mJournal.delete()) {
   2162                 Slog.e(TAG, "Unable to remove backup journal file " + mJournal);
   2163             }
   2164 
   2165             // If everything actually went through and this is the first time we've
   2166             // done a backup, we can now record what the current backup dataset token
   2167             // is.
   2168             if ((mCurrentToken == 0) && (mStatus == BackupConstants.TRANSPORT_OK)) {
   2169                 addBackupTrace("success; recording token");
   2170                 try {
   2171                     mCurrentToken = mTransport.getCurrentRestoreSet();
   2172                     writeRestoreTokens();
   2173                 } catch (RemoteException e) {
   2174                     // nothing for it at this point, unfortunately, but this will be
   2175                     // recorded the next time we fully succeed.
   2176                     addBackupTrace("transport threw returning token");
   2177                 }
   2178             }
   2179 
   2180             // Set up the next backup pass - at this point we can set mBackupRunning
   2181             // to false to allow another pass to fire, because we're done with the
   2182             // state machine sequence and the wakelock is refcounted.
   2183             synchronized (mQueueLock) {
   2184                 mBackupRunning = false;
   2185                 if (mStatus == BackupConstants.TRANSPORT_NOT_INITIALIZED) {
   2186                     // Make sure we back up everything and perform the one-time init
   2187                     clearMetadata();
   2188                     if (DEBUG) Slog.d(TAG, "Server requires init; rerunning");
   2189                     addBackupTrace("init required; rerunning");
   2190                     backupNow();
   2191                 }
   2192             }
   2193 
   2194             // Only once we're entirely finished do we release the wakelock
   2195             clearBackupTrace();
   2196             Slog.i(TAG, "Backup pass finished.");
   2197             mWakelock.release();
   2198         }
   2199 
   2200         // Remove the PM metadata state. This will generate an init on the next pass.
   2201         void clearMetadata() {
   2202             final File pmState = new File(mStateDir, PACKAGE_MANAGER_SENTINEL);
   2203             if (pmState.exists()) pmState.delete();
   2204         }
   2205 
   2206         // Invoke an agent's doBackup() and start a timeout message spinning on the main
   2207         // handler in case it doesn't get back to us.
   2208         int invokeAgentForBackup(String packageName, IBackupAgent agent,
   2209                 IBackupTransport transport) {
   2210             if (DEBUG) Slog.d(TAG, "invokeAgentForBackup on " + packageName);
   2211             addBackupTrace("invoking " + packageName);
   2212 
   2213             mSavedStateName = new File(mStateDir, packageName);
   2214             mBackupDataName = new File(mDataDir, packageName + ".data");
   2215             mNewStateName = new File(mStateDir, packageName + ".new");
   2216 
   2217             mSavedState = null;
   2218             mBackupData = null;
   2219             mNewState = null;
   2220 
   2221             final int token = generateToken();
   2222             try {
   2223                 // Look up the package info & signatures.  This is first so that if it
   2224                 // throws an exception, there's no file setup yet that would need to
   2225                 // be unraveled.
   2226                 if (packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
   2227                     // The metadata 'package' is synthetic; construct one and make
   2228                     // sure our global state is pointed at it
   2229                     mCurrentPackage = new PackageInfo();
   2230                     mCurrentPackage.packageName = packageName;
   2231                 }
   2232 
   2233                 // In a full backup, we pass a null ParcelFileDescriptor as
   2234                 // the saved-state "file". This is by definition an incremental,
   2235                 // so we build a saved state file to pass.
   2236                 mSavedState = ParcelFileDescriptor.open(mSavedStateName,
   2237                         ParcelFileDescriptor.MODE_READ_ONLY |
   2238                         ParcelFileDescriptor.MODE_CREATE);  // Make an empty file if necessary
   2239 
   2240                 mBackupData = ParcelFileDescriptor.open(mBackupDataName,
   2241                         ParcelFileDescriptor.MODE_READ_WRITE |
   2242                         ParcelFileDescriptor.MODE_CREATE |
   2243                         ParcelFileDescriptor.MODE_TRUNCATE);
   2244 
   2245                 if (!SELinux.restorecon(mBackupDataName)) {
   2246                     Slog.e(TAG, "SELinux restorecon failed on " + mBackupDataName);
   2247                 }
   2248 
   2249                 mNewState = ParcelFileDescriptor.open(mNewStateName,
   2250                         ParcelFileDescriptor.MODE_READ_WRITE |
   2251                         ParcelFileDescriptor.MODE_CREATE |
   2252                         ParcelFileDescriptor.MODE_TRUNCATE);
   2253 
   2254                 // Initiate the target's backup pass
   2255                 addBackupTrace("setting timeout");
   2256                 prepareOperationTimeout(token, TIMEOUT_BACKUP_INTERVAL, this);
   2257                 addBackupTrace("calling agent doBackup()");
   2258                 agent.doBackup(mSavedState, mBackupData, mNewState, token, mBackupManagerBinder);
   2259             } catch (Exception e) {
   2260                 Slog.e(TAG, "Error invoking for backup on " + packageName);
   2261                 addBackupTrace("exception: " + e);
   2262                 EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName,
   2263                         e.toString());
   2264                 agentErrorCleanup();
   2265                 return BackupConstants.AGENT_ERROR;
   2266             }
   2267 
   2268             // At this point the agent is off and running.  The next thing to happen will
   2269             // either be a callback from the agent, at which point we'll process its data
   2270             // for transport, or a timeout.  Either way the next phase will happen in
   2271             // response to the TimeoutHandler interface callbacks.
   2272             addBackupTrace("invoke success");
   2273             return BackupConstants.TRANSPORT_OK;
   2274         }
   2275 
   2276         @Override
   2277         public void operationComplete() {
   2278             // Okay, the agent successfully reported back to us.  Spin the data off to the
   2279             // transport and proceed with the next stage.
   2280             if (MORE_DEBUG) Slog.v(TAG, "operationComplete(): sending data to transport for "
   2281                     + mCurrentPackage.packageName);
   2282             mBackupHandler.removeMessages(MSG_TIMEOUT);
   2283             clearAgentState();
   2284             addBackupTrace("operation complete");
   2285 
   2286             ParcelFileDescriptor backupData = null;
   2287             mStatus = BackupConstants.TRANSPORT_OK;
   2288             try {
   2289                 int size = (int) mBackupDataName.length();
   2290                 if (size > 0) {
   2291                     if (mStatus == BackupConstants.TRANSPORT_OK) {
   2292                         backupData = ParcelFileDescriptor.open(mBackupDataName,
   2293                                 ParcelFileDescriptor.MODE_READ_ONLY);
   2294                         addBackupTrace("sending data to transport");
   2295                         mStatus = mTransport.performBackup(mCurrentPackage, backupData);
   2296                     }
   2297 
   2298                     // TODO - We call finishBackup() for each application backed up, because
   2299                     // we need to know now whether it succeeded or failed.  Instead, we should
   2300                     // hold off on finishBackup() until the end, which implies holding off on
   2301                     // renaming *all* the output state files (see below) until that happens.
   2302 
   2303                     addBackupTrace("data delivered: " + mStatus);
   2304                     if (mStatus == BackupConstants.TRANSPORT_OK) {
   2305                         addBackupTrace("finishing op on transport");
   2306                         mStatus = mTransport.finishBackup();
   2307                         addBackupTrace("finished: " + mStatus);
   2308                     }
   2309                 } else {
   2310                     if (DEBUG) Slog.i(TAG, "no backup data written; not calling transport");
   2311                     addBackupTrace("no data to send");
   2312                 }
   2313 
   2314                 // After successful transport, delete the now-stale data
   2315                 // and juggle the files so that next time we supply the agent
   2316                 // with the new state file it just created.
   2317                 if (mStatus == BackupConstants.TRANSPORT_OK) {
   2318                     mBackupDataName.delete();
   2319                     mNewStateName.renameTo(mSavedStateName);
   2320                     EventLog.writeEvent(EventLogTags.BACKUP_PACKAGE,
   2321                             mCurrentPackage.packageName, size);
   2322                     logBackupComplete(mCurrentPackage.packageName);
   2323                 } else {
   2324                     EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE,
   2325                             mCurrentPackage.packageName);
   2326                 }
   2327             } catch (Exception e) {
   2328                 Slog.e(TAG, "Transport error backing up " + mCurrentPackage.packageName, e);
   2329                 EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE,
   2330                         mCurrentPackage.packageName);
   2331                 mStatus = BackupConstants.TRANSPORT_ERROR;
   2332             } finally {
   2333                 try { if (backupData != null) backupData.close(); } catch (IOException e) {}
   2334             }
   2335 
   2336             // If we encountered an error here it's a transport-level failure.  That
   2337             // means we need to halt everything and reschedule everything for next time.
   2338             final BackupState nextState;
   2339             if (mStatus != BackupConstants.TRANSPORT_OK) {
   2340                 revertAndEndBackup();
   2341                 nextState = BackupState.FINAL;
   2342             } else {
   2343                 // Success!  Proceed with the next app if any, otherwise we're done.
   2344                 nextState = (mQueue.isEmpty()) ? BackupState.FINAL : BackupState.RUNNING_QUEUE;
   2345             }
   2346 
   2347             executeNextState(nextState);
   2348         }
   2349 
   2350         @Override
   2351         public void handleTimeout() {
   2352             // Whoops, the current agent timed out running doBackup().  Tidy up and restage
   2353             // it for the next time we run a backup pass.
   2354             // !!! TODO: keep track of failure counts per agent, and blacklist those which
   2355             // fail repeatedly (i.e. have proved themselves to be buggy).
   2356             Slog.e(TAG, "Timeout backing up " + mCurrentPackage.packageName);
   2357             EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, mCurrentPackage.packageName,
   2358                     "timeout");
   2359             addBackupTrace("timeout of " + mCurrentPackage.packageName);
   2360             agentErrorCleanup();
   2361             dataChangedImpl(mCurrentPackage.packageName);
   2362         }
   2363 
   2364         void revertAndEndBackup() {
   2365             if (MORE_DEBUG) Slog.i(TAG, "Reverting backup queue - restaging everything");
   2366             addBackupTrace("transport error; reverting");
   2367             for (BackupRequest request : mOriginalQueue) {
   2368                 dataChangedImpl(request.packageName);
   2369             }
   2370             // We also want to reset the backup schedule based on whatever
   2371             // the transport suggests by way of retry/backoff time.
   2372             restartBackupAlarm();
   2373         }
   2374 
   2375         void agentErrorCleanup() {
   2376             mBackupDataName.delete();
   2377             mNewStateName.delete();
   2378             clearAgentState();
   2379 
   2380             executeNextState(mQueue.isEmpty() ? BackupState.FINAL : BackupState.RUNNING_QUEUE);
   2381         }
   2382 
   2383         // Cleanup common to both success and failure cases
   2384         void clearAgentState() {
   2385             try { if (mSavedState != null) mSavedState.close(); } catch (IOException e) {}
   2386             try { if (mBackupData != null) mBackupData.close(); } catch (IOException e) {}
   2387             try { if (mNewState != null) mNewState.close(); } catch (IOException e) {}
   2388             mSavedState = mBackupData = mNewState = null;
   2389             synchronized (mCurrentOpLock) {
   2390                 mCurrentOperations.clear();
   2391             }
   2392 
   2393             // If this was a pseudopackage there's no associated Activity Manager state
   2394             if (mCurrentPackage.applicationInfo != null) {
   2395                 addBackupTrace("unbinding " + mCurrentPackage.packageName);
   2396                 try {  // unbind even on timeout, just in case
   2397                     mActivityManager.unbindBackupAgent(mCurrentPackage.applicationInfo);
   2398                 } catch (RemoteException e) { /* can't happen; activity manager is local */ }
   2399             }
   2400         }
   2401 
   2402         void restartBackupAlarm() {
   2403             addBackupTrace("setting backup trigger");
   2404             synchronized (mQueueLock) {
   2405                 try {
   2406                     startBackupAlarmsLocked(mTransport.requestBackupTime());
   2407                 } catch (RemoteException e) { /* cannot happen */ }
   2408             }
   2409         }
   2410 
   2411         void executeNextState(BackupState nextState) {
   2412             if (MORE_DEBUG) Slog.i(TAG, " => executing next step on "
   2413                     + this + " nextState=" + nextState);
   2414             addBackupTrace("executeNextState => " + nextState);
   2415             mCurrentState = nextState;
   2416             Message msg = mBackupHandler.obtainMessage(MSG_BACKUP_RESTORE_STEP, this);
   2417             mBackupHandler.sendMessage(msg);
   2418         }
   2419     }
   2420 
   2421 
   2422     // ----- Full backup/restore to a file/socket -----
   2423 
   2424     abstract class ObbServiceClient {
   2425         public IObbBackupService mObbService;
   2426         public void setObbBinder(IObbBackupService binder) {
   2427             mObbService = binder;
   2428         }
   2429     }
   2430 
   2431     class FullBackupObbConnection implements ServiceConnection {
   2432         volatile IObbBackupService mService;
   2433 
   2434         FullBackupObbConnection() {
   2435             mService = null;
   2436         }
   2437 
   2438         public void establish() {
   2439             if (DEBUG) Slog.i(TAG, "Initiating bind of OBB service on " + this);
   2440             Intent obbIntent = new Intent().setComponent(new ComponentName(
   2441                     "com.android.sharedstoragebackup",
   2442                     "com.android.sharedstoragebackup.ObbBackupService"));
   2443             BackupManagerService.this.mContext.bindService(
   2444                     obbIntent, this, Context.BIND_AUTO_CREATE);
   2445         }
   2446 
   2447         public void tearDown() {
   2448             BackupManagerService.this.mContext.unbindService(this);
   2449         }
   2450 
   2451         public boolean backupObbs(PackageInfo pkg, OutputStream out) {
   2452             boolean success = false;
   2453             waitForConnection();
   2454 
   2455             ParcelFileDescriptor[] pipes = null;
   2456             try {
   2457                 pipes = ParcelFileDescriptor.createPipe();
   2458                 int token = generateToken();
   2459                 prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL, null);
   2460                 mService.backupObbs(pkg.packageName, pipes[1], token, mBackupManagerBinder);
   2461                 routeSocketDataToOutput(pipes[0], out);
   2462                 success = waitUntilOperationComplete(token);
   2463             } catch (Exception e) {
   2464                 Slog.w(TAG, "Unable to back up OBBs for " + pkg, e);
   2465             } finally {
   2466                 try {
   2467                     out.flush();
   2468                     if (pipes != null) {
   2469                         if (pipes[0] != null) pipes[0].close();
   2470                         if (pipes[1] != null) pipes[1].close();
   2471                     }
   2472                 } catch (IOException e) {
   2473                     Slog.w(TAG, "I/O error closing down OBB backup", e);
   2474                 }
   2475             }
   2476             return success;
   2477         }
   2478 
   2479         public void restoreObbFile(String pkgName, ParcelFileDescriptor data,
   2480                 long fileSize, int type, String path, long mode, long mtime,
   2481                 int token, IBackupManager callbackBinder) {
   2482             waitForConnection();
   2483 
   2484             try {
   2485                 mService.restoreObbFile(pkgName, data, fileSize, type, path, mode, mtime,
   2486                         token, callbackBinder);
   2487             } catch (Exception e) {
   2488                 Slog.w(TAG, "Unable to restore OBBs for " + pkgName, e);
   2489             }
   2490         }
   2491 
   2492         private void waitForConnection() {
   2493             synchronized (this) {
   2494                 while (mService == null) {
   2495                     if (DEBUG) Slog.i(TAG, "...waiting for OBB service binding...");
   2496                     try {
   2497                         this.wait();
   2498                     } catch (InterruptedException e) { /* never interrupted */ }
   2499                 }
   2500                 if (DEBUG) Slog.i(TAG, "Connected to OBB service; continuing");
   2501             }
   2502         }
   2503 
   2504         @Override
   2505         public void onServiceConnected(ComponentName name, IBinder service) {
   2506             synchronized (this) {
   2507                 mService = IObbBackupService.Stub.asInterface(service);
   2508                 if (DEBUG) Slog.i(TAG, "OBB service connection " + mService
   2509                         + " connected on " + this);
   2510                 this.notifyAll();
   2511             }
   2512         }
   2513 
   2514         @Override
   2515         public void onServiceDisconnected(ComponentName name) {
   2516             synchronized (this) {
   2517                 mService = null;
   2518                 if (DEBUG) Slog.i(TAG, "OBB service connection disconnected on " + this);
   2519                 this.notifyAll();
   2520             }
   2521         }
   2522 
   2523     }
   2524 
   2525     private void routeSocketDataToOutput(ParcelFileDescriptor inPipe, OutputStream out)
   2526             throws IOException {
   2527         FileInputStream raw = new FileInputStream(inPipe.getFileDescriptor());
   2528         DataInputStream in = new DataInputStream(raw);
   2529 
   2530         byte[] buffer = new byte[32 * 1024];
   2531         int chunkTotal;
   2532         while ((chunkTotal = in.readInt()) > 0) {
   2533             while (chunkTotal > 0) {
   2534                 int toRead = (chunkTotal > buffer.length) ? buffer.length : chunkTotal;
   2535                 int nRead = in.read(buffer, 0, toRead);
   2536                 out.write(buffer, 0, nRead);
   2537                 chunkTotal -= nRead;
   2538             }
   2539         }
   2540     }
   2541 
   2542     class PerformFullBackupTask extends ObbServiceClient implements Runnable {
   2543         ParcelFileDescriptor mOutputFile;
   2544         DeflaterOutputStream mDeflater;
   2545         IFullBackupRestoreObserver mObserver;
   2546         boolean mIncludeApks;
   2547         boolean mIncludeObbs;
   2548         boolean mIncludeShared;
   2549         boolean mAllApps;
   2550         final boolean mIncludeSystem;
   2551         String[] mPackages;
   2552         String mCurrentPassword;
   2553         String mEncryptPassword;
   2554         AtomicBoolean mLatchObject;
   2555         File mFilesDir;
   2556         File mManifestFile;
   2557 
   2558 
   2559         class FullBackupRunner implements Runnable {
   2560             PackageInfo mPackage;
   2561             IBackupAgent mAgent;
   2562             ParcelFileDescriptor mPipe;
   2563             int mToken;
   2564             boolean mSendApk;
   2565             boolean mWriteManifest;
   2566 
   2567             FullBackupRunner(PackageInfo pack, IBackupAgent agent, ParcelFileDescriptor pipe,
   2568                     int token, boolean sendApk, boolean writeManifest)  throws IOException {
   2569                 mPackage = pack;
   2570                 mAgent = agent;
   2571                 mPipe = ParcelFileDescriptor.dup(pipe.getFileDescriptor());
   2572                 mToken = token;
   2573                 mSendApk = sendApk;
   2574                 mWriteManifest = writeManifest;
   2575             }
   2576 
   2577             @Override
   2578             public void run() {
   2579                 try {
   2580                     BackupDataOutput output = new BackupDataOutput(
   2581                             mPipe.getFileDescriptor());
   2582 
   2583                     if (mWriteManifest) {
   2584                         if (MORE_DEBUG) Slog.d(TAG, "Writing manifest for " + mPackage.packageName);
   2585                         writeAppManifest(mPackage, mManifestFile, mSendApk);
   2586                         FullBackup.backupToTar(mPackage.packageName, null, null,
   2587                                 mFilesDir.getAbsolutePath(),
   2588                                 mManifestFile.getAbsolutePath(),
   2589                                 output);
   2590                     }
   2591 
   2592                     if (mSendApk) {
   2593                         writeApkToBackup(mPackage, output);
   2594                     }
   2595 
   2596                     if (DEBUG) Slog.d(TAG, "Calling doFullBackup() on " + mPackage.packageName);
   2597                     prepareOperationTimeout(mToken, TIMEOUT_FULL_BACKUP_INTERVAL, null);
   2598                     mAgent.doFullBackup(mPipe, mToken, mBackupManagerBinder);
   2599                 } catch (IOException e) {
   2600                     Slog.e(TAG, "Error running full backup for " + mPackage.packageName);
   2601                 } catch (RemoteException e) {
   2602                     Slog.e(TAG, "Remote agent vanished during full backup of "
   2603                             + mPackage.packageName);
   2604                 } finally {
   2605                     try {
   2606                         mPipe.close();
   2607                     } catch (IOException e) {}
   2608                 }
   2609             }
   2610         }
   2611 
   2612         PerformFullBackupTask(ParcelFileDescriptor fd, IFullBackupRestoreObserver observer,
   2613                 boolean includeApks, boolean includeObbs, boolean includeShared,
   2614                 String curPassword, String encryptPassword, boolean doAllApps,
   2615                 boolean doSystem, String[] packages, AtomicBoolean latch) {
   2616             mOutputFile = fd;
   2617             mObserver = observer;
   2618             mIncludeApks = includeApks;
   2619             mIncludeObbs = includeObbs;
   2620             mIncludeShared = includeShared;
   2621             mAllApps = doAllApps;
   2622             mIncludeSystem = doSystem;
   2623             mPackages = packages;
   2624             mCurrentPassword = curPassword;
   2625             // when backing up, if there is a current backup password, we require that
   2626             // the user use a nonempty encryption password as well.  if one is supplied
   2627             // in the UI we use that, but if the UI was left empty we fall back to the
   2628             // current backup password (which was supplied by the user as well).
   2629             if (encryptPassword == null || "".equals(encryptPassword)) {
   2630                 mEncryptPassword = curPassword;
   2631             } else {
   2632                 mEncryptPassword = encryptPassword;
   2633             }
   2634             mLatchObject = latch;
   2635 
   2636             mFilesDir = new File("/data/system");
   2637             mManifestFile = new File(mFilesDir, BACKUP_MANIFEST_FILENAME);
   2638         }
   2639 
   2640         @Override
   2641         public void run() {
   2642             Slog.i(TAG, "--- Performing full-dataset backup ---");
   2643 
   2644             List<PackageInfo> packagesToBackup = new ArrayList<PackageInfo>();
   2645             FullBackupObbConnection obbConnection = new FullBackupObbConnection();
   2646             obbConnection.establish();  // we'll want this later
   2647 
   2648             sendStartBackup();
   2649 
   2650             // doAllApps supersedes the package set if any
   2651             if (mAllApps) {
   2652                 packagesToBackup = mPackageManager.getInstalledPackages(
   2653                         PackageManager.GET_SIGNATURES);
   2654                 // Exclude system apps if we've been asked to do so
   2655                 if (mIncludeSystem == false) {
   2656                     for (int i = 0; i < packagesToBackup.size(); ) {
   2657                         PackageInfo pkg = packagesToBackup.get(i);
   2658                         if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
   2659                             packagesToBackup.remove(i);
   2660                         } else {
   2661                             i++;
   2662                         }
   2663                     }
   2664                 }
   2665             }
   2666 
   2667             // Now process the command line argument packages, if any. Note that explicitly-
   2668             // named system-partition packages will be included even if includeSystem was
   2669             // set to false.
   2670             if (mPackages != null) {
   2671                 for (String pkgName : mPackages) {
   2672                     try {
   2673                         packagesToBackup.add(mPackageManager.getPackageInfo(pkgName,
   2674                                 PackageManager.GET_SIGNATURES));
   2675                     } catch (NameNotFoundException e) {
   2676                         Slog.w(TAG, "Unknown package " + pkgName + ", skipping");
   2677                     }
   2678                 }
   2679             }
   2680 
   2681             // Cull any packages that have indicated that backups are not permitted, as well
   2682             // as any explicit mention of the 'special' shared-storage agent package (we
   2683             // handle that one at the end).
   2684             for (int i = 0; i < packagesToBackup.size(); ) {
   2685                 PackageInfo pkg = packagesToBackup.get(i);
   2686                 if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0
   2687                         || pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE)) {
   2688                     packagesToBackup.remove(i);
   2689                 } else {
   2690                     i++;
   2691                 }
   2692             }
   2693 
   2694             // Cull any packages that run as system-domain uids but do not define their
   2695             // own backup agents
   2696             for (int i = 0; i < packagesToBackup.size(); ) {
   2697                 PackageInfo pkg = packagesToBackup.get(i);
   2698                 if ((pkg.applicationInfo.uid < Process.FIRST_APPLICATION_UID)
   2699                         && (pkg.applicationInfo.backupAgentName == null)) {
   2700                     if (MORE_DEBUG) {
   2701                         Slog.i(TAG, "... ignoring non-agent system package " + pkg.packageName);
   2702                     }
   2703                     packagesToBackup.remove(i);
   2704                 } else {
   2705                     i++;
   2706                 }
   2707             }
   2708 
   2709             FileOutputStream ofstream = new FileOutputStream(mOutputFile.getFileDescriptor());
   2710             OutputStream out = null;
   2711 
   2712             PackageInfo pkg = null;
   2713             try {
   2714                 boolean encrypting = (mEncryptPassword != null && mEncryptPassword.length() > 0);
   2715                 boolean compressing = COMPRESS_FULL_BACKUPS;
   2716                 OutputStream finalOutput = ofstream;
   2717 
   2718                 // Verify that the given password matches the currently-active
   2719                 // backup password, if any
   2720                 if (hasBackupPassword()) {
   2721                     if (!passwordMatchesSaved(mCurrentPassword, PBKDF2_HASH_ROUNDS)) {
   2722                         if (DEBUG) Slog.w(TAG, "Backup password mismatch; aborting");
   2723                         return;
   2724                     }
   2725                 }
   2726 
   2727                 // Write the global file header.  All strings are UTF-8 encoded; lines end
   2728                 // with a '\n' byte.  Actual backup data begins immediately following the
   2729                 // final '\n'.
   2730                 //
   2731                 // line 1: "ANDROID BACKUP"
   2732                 // line 2: backup file format version, currently "1"
   2733                 // line 3: compressed?  "0" if not compressed, "1" if compressed.
   2734                 // line 4: name of encryption algorithm [currently only "none" or "AES-256"]
   2735                 //
   2736                 // When line 4 is not "none", then additional header data follows:
   2737                 //
   2738                 // line 5: user password salt [hex]
   2739                 // line 6: master key checksum salt [hex]
   2740                 // line 7: number of PBKDF2 rounds to use (same for user & master) [decimal]
   2741                 // line 8: IV of the user key [hex]
   2742                 // line 9: master key blob [hex]
   2743                 //     IV of the master key, master key itself, master key checksum hash
   2744                 //
   2745                 // The master key checksum is the master key plus its checksum salt, run through
   2746                 // 10k rounds of PBKDF2.  This is used to verify that the user has supplied the
   2747                 // correct password for decrypting the archive:  the master key decrypted from
   2748                 // the archive using the user-supplied password is also run through PBKDF2 in
   2749                 // this way, and if the result does not match the checksum as stored in the
   2750                 // archive, then we know that the user-supplied password does not match the
   2751                 // archive's.
   2752                 StringBuilder headerbuf = new StringBuilder(1024);
   2753 
   2754                 headerbuf.append(BACKUP_FILE_HEADER_MAGIC);
   2755                 headerbuf.append(BACKUP_FILE_VERSION); // integer, no trailing \n
   2756                 headerbuf.append(compressing ? "\n1\n" : "\n0\n");
   2757 
   2758                 try {
   2759                     // Set up the encryption stage if appropriate, and emit the correct header
   2760                     if (encrypting) {
   2761                         finalOutput = emitAesBackupHeader(headerbuf, finalOutput);
   2762                     } else {
   2763                         headerbuf.append("none\n");
   2764                     }
   2765 
   2766                     byte[] header = headerbuf.toString().getBytes("UTF-8");
   2767                     ofstream.write(header);
   2768 
   2769                     // Set up the compression stage feeding into the encryption stage (if any)
   2770                     if (compressing) {
   2771                         Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION);
   2772                         finalOutput = new DeflaterOutputStream(finalOutput, deflater, true);
   2773                     }
   2774 
   2775                     out = finalOutput;
   2776                 } catch (Exception e) {
   2777                     // Should never happen!
   2778                     Slog.e(TAG, "Unable to emit archive header", e);
   2779                     return;
   2780                 }
   2781 
   2782                 // Shared storage if requested
   2783                 if (mIncludeShared) {
   2784                     try {
   2785                         pkg = mPackageManager.getPackageInfo(SHARED_BACKUP_AGENT_PACKAGE, 0);
   2786                         packagesToBackup.add(pkg);
   2787                     } catch (NameNotFoundException e) {
   2788                         Slog.e(TAG, "Unable to find shared-storage backup handler");
   2789                     }
   2790                 }
   2791 
   2792                 // Now back up the app data via the agent mechanism
   2793                 int N = packagesToBackup.size();
   2794                 for (int i = 0; i < N; i++) {
   2795                     pkg = packagesToBackup.get(i);
   2796                     backupOnePackage(pkg, out);
   2797 
   2798                     // after the app's agent runs to handle its private filesystem
   2799                     // contents, back up any OBB content it has on its behalf.
   2800                     if (mIncludeObbs) {
   2801                         boolean obbOkay = obbConnection.backupObbs(pkg, out);
   2802                         if (!obbOkay) {
   2803                             throw new RuntimeException("Failure writing OBB stack for " + pkg);
   2804                         }
   2805                     }
   2806                 }
   2807 
   2808                 // Done!
   2809                 finalizeBackup(out);
   2810             } catch (RemoteException e) {
   2811                 Slog.e(TAG, "App died during full backup");
   2812             } catch (Exception e) {
   2813                 Slog.e(TAG, "Internal exception during full backup", e);
   2814             } finally {
   2815                 tearDown(pkg);
   2816                 try {
   2817                     if (out != null) out.close();
   2818                     mOutputFile.close();
   2819                 } catch (IOException e) {
   2820                     /* nothing we can do about this */
   2821                 }
   2822                 synchronized (mCurrentOpLock) {
   2823                     mCurrentOperations.clear();
   2824                 }
   2825                 synchronized (mLatchObject) {
   2826                     mLatchObject.set(true);
   2827                     mLatchObject.notifyAll();
   2828                 }
   2829                 sendEndBackup();
   2830                 obbConnection.tearDown();
   2831                 if (DEBUG) Slog.d(TAG, "Full backup pass complete.");
   2832                 mWakelock.release();
   2833             }
   2834         }
   2835 
   2836         private OutputStream emitAesBackupHeader(StringBuilder headerbuf,
   2837                 OutputStream ofstream) throws Exception {
   2838             // User key will be used to encrypt the master key.
   2839             byte[] newUserSalt = randomBytes(PBKDF2_SALT_SIZE);
   2840             SecretKey userKey = buildPasswordKey(mEncryptPassword, newUserSalt,
   2841                     PBKDF2_HASH_ROUNDS);
   2842 
   2843             // the master key is random for each backup
   2844             byte[] masterPw = new byte[256 / 8];
   2845             mRng.nextBytes(masterPw);
   2846             byte[] checksumSalt = randomBytes(PBKDF2_SALT_SIZE);
   2847 
   2848             // primary encryption of the datastream with the random key
   2849             Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
   2850             SecretKeySpec masterKeySpec = new SecretKeySpec(masterPw, "AES");
   2851             c.init(Cipher.ENCRYPT_MODE, masterKeySpec);
   2852             OutputStream finalOutput = new CipherOutputStream(ofstream, c);
   2853 
   2854             // line 4: name of encryption algorithm
   2855             headerbuf.append(ENCRYPTION_ALGORITHM_NAME);
   2856             headerbuf.append('\n');
   2857             // line 5: user password salt [hex]
   2858             headerbuf.append(byteArrayToHex(newUserSalt));
   2859             headerbuf.append('\n');
   2860             // line 6: master key checksum salt [hex]
   2861             headerbuf.append(byteArrayToHex(checksumSalt));
   2862             headerbuf.append('\n');
   2863             // line 7: number of PBKDF2 rounds used [decimal]
   2864             headerbuf.append(PBKDF2_HASH_ROUNDS);
   2865             headerbuf.append('\n');
   2866 
   2867             // line 8: IV of the user key [hex]
   2868             Cipher mkC = Cipher.getInstance("AES/CBC/PKCS5Padding");
   2869             mkC.init(Cipher.ENCRYPT_MODE, userKey);
   2870 
   2871             byte[] IV = mkC.getIV();
   2872             headerbuf.append(byteArrayToHex(IV));
   2873             headerbuf.append('\n');
   2874 
   2875             // line 9: master IV + key blob, encrypted by the user key [hex].  Blob format:
   2876             //    [byte] IV length = Niv
   2877             //    [array of Niv bytes] IV itself
   2878             //    [byte] master key length = Nmk
   2879             //    [array of Nmk bytes] master key itself
   2880             //    [byte] MK checksum hash length = Nck
   2881             //    [array of Nck bytes] master key checksum hash
   2882             //
   2883             // The checksum is the (master key + checksum salt), run through the
   2884             // stated number of PBKDF2 rounds
   2885             IV = c.getIV();
   2886             byte[] mk = masterKeySpec.getEncoded();
   2887             byte[] checksum = makeKeyChecksum(masterKeySpec.getEncoded(),
   2888                     checksumSalt, PBKDF2_HASH_ROUNDS);
   2889 
   2890             ByteArrayOutputStream blob = new ByteArrayOutputStream(IV.length + mk.length
   2891                     + checksum.length + 3);
   2892             DataOutputStream mkOut = new DataOutputStream(blob);
   2893             mkOut.writeByte(IV.length);
   2894             mkOut.write(IV);
   2895             mkOut.writeByte(mk.length);
   2896             mkOut.write(mk);
   2897             mkOut.writeByte(checksum.length);
   2898             mkOut.write(checksum);
   2899             mkOut.flush();
   2900             byte[] encryptedMk = mkC.doFinal(blob.toByteArray());
   2901             headerbuf.append(byteArrayToHex(encryptedMk));
   2902             headerbuf.append('\n');
   2903 
   2904             return finalOutput;
   2905         }
   2906 
   2907         private void backupOnePackage(PackageInfo pkg, OutputStream out)
   2908                 throws RemoteException {
   2909             Slog.d(TAG, "Binding to full backup agent : " + pkg.packageName);
   2910 
   2911             IBackupAgent agent = bindToAgentSynchronous(pkg.applicationInfo,
   2912                     IApplicationThread.BACKUP_MODE_FULL);
   2913             if (agent != null) {
   2914                 ParcelFileDescriptor[] pipes = null;
   2915                 try {
   2916                     pipes = ParcelFileDescriptor.createPipe();
   2917 
   2918                     ApplicationInfo app = pkg.applicationInfo;
   2919                     final boolean isSharedStorage = pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE);
   2920                     final boolean sendApk = mIncludeApks
   2921                             && !isSharedStorage
   2922                             && ((app.flags & ApplicationInfo.FLAG_FORWARD_LOCK) == 0)
   2923                             && ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0 ||
   2924                                 (app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
   2925 
   2926                     sendOnBackupPackage(isSharedStorage ? "Shared storage" : pkg.packageName);
   2927 
   2928                     final int token = generateToken();
   2929                     FullBackupRunner runner = new FullBackupRunner(pkg, agent, pipes[1],
   2930                             token, sendApk, !isSharedStorage);
   2931                     pipes[1].close();   // the runner has dup'd it
   2932                     pipes[1] = null;
   2933                     Thread t = new Thread(runner);
   2934                     t.start();
   2935 
   2936                     // Now pull data from the app and stuff it into the compressor
   2937                     try {
   2938                         routeSocketDataToOutput(pipes[0], out);
   2939                     } catch (IOException e) {
   2940                         Slog.i(TAG, "Caught exception reading from agent", e);
   2941                     }
   2942 
   2943                     if (!waitUntilOperationComplete(token)) {
   2944                         Slog.e(TAG, "Full backup failed on package " + pkg.packageName);
   2945                     } else {
   2946                         if (DEBUG) Slog.d(TAG, "Full package backup success: " + pkg.packageName);
   2947                     }
   2948 
   2949                 } catch (IOException e) {
   2950                     Slog.e(TAG, "Error backing up " + pkg.packageName, e);
   2951                 } finally {
   2952                     try {
   2953                         // flush after every package
   2954                         out.flush();
   2955                         if (pipes != null) {
   2956                             if (pipes[0] != null) pipes[0].close();
   2957                             if (pipes[1] != null) pipes[1].close();
   2958                         }
   2959                     } catch (IOException e) {
   2960                         Slog.w(TAG, "Error bringing down backup stack");
   2961                     }
   2962                 }
   2963             } else {
   2964                 Slog.w(TAG, "Unable to bind to full agent for " + pkg.packageName);
   2965             }
   2966             tearDown(pkg);
   2967         }
   2968 
   2969         private void writeApkToBackup(PackageInfo pkg, BackupDataOutput output) {
   2970             // Forward-locked apps, system-bundled .apks, etc are filtered out before we get here
   2971             final String appSourceDir = pkg.applicationInfo.sourceDir;
   2972             final String apkDir = new File(appSourceDir).getParent();
   2973             FullBackup.backupToTar(pkg.packageName, FullBackup.APK_TREE_TOKEN, null,
   2974                     apkDir, appSourceDir, output);
   2975 
   2976             // TODO: migrate this to SharedStorageBackup, since AID_SYSTEM
   2977             // doesn't have access to external storage.
   2978 
   2979             // Save associated .obb content if it exists and we did save the apk
   2980             // check for .obb and save those too
   2981             final UserEnvironment userEnv = new UserEnvironment(UserHandle.USER_OWNER);
   2982             final File obbDir = userEnv.buildExternalStorageAppObbDirs(pkg.packageName)[0];
   2983             if (obbDir != null) {
   2984                 if (MORE_DEBUG) Log.i(TAG, "obb dir: " + obbDir.getAbsolutePath());
   2985                 File[] obbFiles = obbDir.listFiles();
   2986                 if (obbFiles != null) {
   2987                     final String obbDirName = obbDir.getAbsolutePath();
   2988                     for (File obb : obbFiles) {
   2989                         FullBackup.backupToTar(pkg.packageName, FullBackup.OBB_TREE_TOKEN, null,
   2990                                 obbDirName, obb.getAbsolutePath(), output);
   2991                     }
   2992                 }
   2993             }
   2994         }
   2995 
   2996         private void finalizeBackup(OutputStream out) {
   2997             try {
   2998                 // A standard 'tar' EOF sequence: two 512-byte blocks of all zeroes.
   2999                 byte[] eof = new byte[512 * 2]; // newly allocated == zero filled
   3000                 out.write(eof);
   3001             } catch (IOException e) {
   3002                 Slog.w(TAG, "Error attempting to finalize backup stream");
   3003             }
   3004         }
   3005 
   3006         private void writeAppManifest(PackageInfo pkg, File manifestFile, boolean withApk)
   3007                 throws IOException {
   3008             // Manifest format. All data are strings ending in LF:
   3009             //     BACKUP_MANIFEST_VERSION, currently 1
   3010             //
   3011             // Version 1:
   3012             //     package name
   3013             //     package's versionCode
   3014             //     platform versionCode
   3015             //     getInstallerPackageName() for this package (maybe empty)
   3016             //     boolean: "1" if archive includes .apk; any other string means not
   3017             //     number of signatures == N
   3018             // N*:    signature byte array in ascii format per Signature.toCharsString()
   3019             StringBuilder builder = new StringBuilder(4096);
   3020             StringBuilderPrinter printer = new StringBuilderPrinter(builder);
   3021 
   3022             printer.println(Integer.toString(BACKUP_MANIFEST_VERSION));
   3023             printer.println(pkg.packageName);
   3024             printer.println(Integer.toString(pkg.versionCode));
   3025             printer.println(Integer.toString(Build.VERSION.SDK_INT));
   3026 
   3027             String installerName = mPackageManager.getInstallerPackageName(pkg.packageName);
   3028             printer.println((installerName != null) ? installerName : "");
   3029 
   3030             printer.println(withApk ? "1" : "0");
   3031             if (pkg.signatures == null) {
   3032                 printer.println("0");
   3033             } else {
   3034                 printer.println(Integer.toString(pkg.signatures.length));
   3035                 for (Signature sig : pkg.signatures) {
   3036                     printer.println(sig.toCharsString());
   3037                 }
   3038             }
   3039 
   3040             FileOutputStream outstream = new FileOutputStream(manifestFile);
   3041             outstream.write(builder.toString().getBytes());
   3042             outstream.close();
   3043         }
   3044 
   3045         private void tearDown(PackageInfo pkg) {
   3046             if (pkg != null) {
   3047                 final ApplicationInfo app = pkg.applicationInfo;
   3048                 if (app != null) {
   3049                     try {
   3050                         // unbind and tidy up even on timeout or failure, just in case
   3051                         mActivityManager.unbindBackupAgent(app);
   3052 
   3053                         // The agent was running with a stub Application object, so shut it down.
   3054                         if (app.uid != Process.SYSTEM_UID
   3055                                 && app.uid != Process.PHONE_UID) {
   3056                             if (MORE_DEBUG) Slog.d(TAG, "Backup complete, killing host process");
   3057                             mActivityManager.killApplicationProcess(app.processName, app.uid);
   3058                         } else {
   3059                             if (MORE_DEBUG) Slog.d(TAG, "Not killing after restore: " + app.processName);
   3060                         }
   3061                     } catch (RemoteException e) {
   3062                         Slog.d(TAG, "Lost app trying to shut down");
   3063                     }
   3064                 }
   3065             }
   3066         }
   3067 
   3068         // wrappers for observer use
   3069         void sendStartBackup() {
   3070             if (mObserver != null) {
   3071                 try {
   3072                     mObserver.onStartBackup();
   3073                 } catch (RemoteException e) {
   3074                     Slog.w(TAG, "full backup observer went away: startBackup");
   3075                     mObserver = null;
   3076                 }
   3077             }
   3078         }
   3079 
   3080         void sendOnBackupPackage(String name) {
   3081             if (mObserver != null) {
   3082                 try {
   3083                     // TODO: use a more user-friendly name string
   3084                     mObserver.onBackupPackage(name);
   3085                 } catch (RemoteException e) {
   3086                     Slog.w(TAG, "full backup observer went away: backupPackage");
   3087                     mObserver = null;
   3088                 }
   3089             }
   3090         }
   3091 
   3092         void sendEndBackup() {
   3093             if (mObserver != null) {
   3094                 try {
   3095                     mObserver.onEndBackup();
   3096                 } catch (RemoteException e) {
   3097                     Slog.w(TAG, "full backup observer went away: endBackup");
   3098                     mObserver = null;
   3099                 }
   3100             }
   3101         }
   3102     }
   3103 
   3104 
   3105     // ----- Full restore from a file/socket -----
   3106 
   3107     // Description of a file in the restore datastream
   3108     static class FileMetadata {
   3109         String packageName;             // name of the owning app
   3110         String installerPackageName;    // name of the market-type app that installed the owner
   3111         int type;                       // e.g. BackupAgent.TYPE_DIRECTORY
   3112         String domain;                  // e.g. FullBackup.DATABASE_TREE_TOKEN
   3113         String path;                    // subpath within the semantic domain
   3114         long mode;                      // e.g. 0666 (actually int)
   3115         long mtime;                     // last mod time, UTC time_t (actually int)
   3116         long size;                      // bytes of content
   3117 
   3118         @Override
   3119         public String toString() {
   3120             StringBuilder sb = new StringBuilder(128);
   3121             sb.append("FileMetadata{");
   3122             sb.append(packageName); sb.append(',');
   3123             sb.append(type); sb.append(',');
   3124             sb.append(domain); sb.append(':'); sb.append(path); sb.append(',');
   3125             sb.append(size);
   3126             sb.append('}');
   3127             return sb.toString();
   3128         }
   3129     }
   3130 
   3131     enum RestorePolicy {
   3132         IGNORE,
   3133         ACCEPT,
   3134         ACCEPT_IF_APK
   3135     }
   3136 
   3137     class PerformFullRestoreTask extends ObbServiceClient implements Runnable {
   3138         ParcelFileDescriptor mInputFile;
   3139         String mCurrentPassword;
   3140         String mDecryptPassword;
   3141         IFullBackupRestoreObserver mObserver;
   3142         AtomicBoolean mLatchObject;
   3143         IBackupAgent mAgent;
   3144         String mAgentPackage;
   3145         ApplicationInfo mTargetApp;
   3146         FullBackupObbConnection mObbConnection = null;
   3147         ParcelFileDescriptor[] mPipes = null;
   3148 
   3149         long mBytes;
   3150 
   3151         // possible handling states for a given package in the restore dataset
   3152         final HashMap<String, RestorePolicy> mPackagePolicies
   3153                 = new HashMap<String, RestorePolicy>();
   3154 
   3155         // installer package names for each encountered app, derived from the manifests
   3156         final HashMap<String, String> mPackageInstallers = new HashMap<String, String>();
   3157 
   3158         // Signatures for a given package found in its manifest file
   3159         final HashMap<String, Signature[]> mManifestSignatures
   3160                 = new HashMap<String, Signature[]>();
   3161 
   3162         // Packages we've already wiped data on when restoring their first file
   3163         final HashSet<String> mClearedPackages = new HashSet<String>();
   3164 
   3165         PerformFullRestoreTask(ParcelFileDescriptor fd, String curPassword, String decryptPassword,
   3166                 IFullBackupRestoreObserver observer, AtomicBoolean latch) {
   3167             mInputFile = fd;
   3168             mCurrentPassword = curPassword;
   3169             mDecryptPassword = decryptPassword;
   3170             mObserver = observer;
   3171             mLatchObject = latch;
   3172             mAgent = null;
   3173             mAgentPackage = null;
   3174             mTargetApp = null;
   3175             mObbConnection = new FullBackupObbConnection();
   3176 
   3177             // Which packages we've already wiped data on.  We prepopulate this
   3178             // with a whitelist of packages known to be unclearable.
   3179             mClearedPackages.add("android");
   3180             mClearedPackages.add("com.android.providers.settings");
   3181 
   3182         }
   3183 
   3184         class RestoreFileRunnable implements Runnable {
   3185             IBackupAgent mAgent;
   3186             FileMetadata mInfo;
   3187             ParcelFileDescriptor mSocket;
   3188             int mToken;
   3189 
   3190             RestoreFileRunnable(IBackupAgent agent, FileMetadata info,
   3191                     ParcelFileDescriptor socket, int token) throws IOException {
   3192                 mAgent = agent;
   3193                 mInfo = info;
   3194                 mToken = token;
   3195 
   3196                 // This class is used strictly for process-local binder invocations.  The
   3197                 // semantics of ParcelFileDescriptor differ in this case; in particular, we
   3198                 // do not automatically get a 'dup'ed descriptor that we can can continue
   3199                 // to use asynchronously from the caller.  So, we make sure to dup it ourselves
   3200                 // before proceeding to do the restore.
   3201                 mSocket = ParcelFileDescriptor.dup(socket.getFileDescriptor());
   3202             }
   3203 
   3204             @Override
   3205             public void run() {
   3206                 try {
   3207                     mAgent.doRestoreFile(mSocket, mInfo.size, mInfo.type,
   3208                             mInfo.domain, mInfo.path, mInfo.mode, mInfo.mtime,
   3209                             mToken, mBackupManagerBinder);
   3210                 } catch (RemoteException e) {
   3211                     // never happens; this is used strictly for local binder calls
   3212                 }
   3213             }
   3214         }
   3215 
   3216         @Override
   3217         public void run() {
   3218             Slog.i(TAG, "--- Performing full-dataset restore ---");
   3219             mObbConnection.establish();
   3220             sendStartRestore();
   3221 
   3222             // Are we able to restore shared-storage data?
   3223             if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
   3224                 mPackagePolicies.put(SHARED_BACKUP_AGENT_PACKAGE, RestorePolicy.ACCEPT);
   3225             }
   3226 
   3227             FileInputStream rawInStream = null;
   3228             DataInputStream rawDataIn = null;
   3229             try {
   3230                 if (hasBackupPassword()) {
   3231                     if (!passwordMatchesSaved(mCurrentPassword, PBKDF2_HASH_ROUNDS)) {
   3232                         if (DEBUG) Slog.w(TAG, "Backup password mismatch; aborting");
   3233                         return;
   3234                     }
   3235                 }
   3236 
   3237                 mBytes = 0;
   3238                 byte[] buffer = new byte[32 * 1024];
   3239                 rawInStream = new FileInputStream(mInputFile.getFileDescriptor());
   3240                 rawDataIn = new DataInputStream(rawInStream);
   3241 
   3242                 // First, parse out the unencrypted/uncompressed header
   3243                 boolean compressed = false;
   3244                 InputStream preCompressStream = rawInStream;
   3245                 final InputStream in;
   3246 
   3247                 boolean okay = false;
   3248                 final int headerLen = BACKUP_FILE_HEADER_MAGIC.length();
   3249                 byte[] streamHeader = new byte[headerLen];
   3250                 rawDataIn.readFully(streamHeader);
   3251                 byte[] magicBytes = BACKUP_FILE_HEADER_MAGIC.getBytes("UTF-8");
   3252                 if (Arrays.equals(magicBytes, streamHeader)) {
   3253                     // okay, header looks good.  now parse out the rest of the fields.
   3254                     String s = readHeaderLine(rawInStream);
   3255                     if (Integer.parseInt(s) == BACKUP_FILE_VERSION) {
   3256                         // okay, it's a version we recognize
   3257                         s = readHeaderLine(rawInStream);
   3258                         compressed = (Integer.parseInt(s) != 0);
   3259                         s = readHeaderLine(rawInStream);
   3260                         if (s.equals("none")) {
   3261                             // no more header to parse; we're good to go
   3262                             okay = true;
   3263                         } else if (mDecryptPassword != null && mDecryptPassword.length() > 0) {
   3264                             preCompressStream = decodeAesHeaderAndInitialize(s, rawInStream);
   3265                             if (preCompressStream != null) {
   3266                                 okay = true;
   3267                             }
   3268                         } else Slog.w(TAG, "Archive is encrypted but no password given");
   3269                     } else Slog.w(TAG, "Wrong header version: " + s);
   3270                 } else Slog.w(TAG, "Didn't read the right header magic");
   3271 
   3272                 if (!okay) {
   3273                     Slog.w(TAG, "Invalid restore data; aborting.");
   3274                     return;
   3275                 }
   3276 
   3277                 // okay, use the right stream layer based on compression
   3278                 in = (compressed) ? new InflaterInputStream(preCompressStream) : preCompressStream;
   3279 
   3280                 boolean didRestore;
   3281                 do {
   3282                     didRestore = restoreOneFile(in, buffer);
   3283                 } while (didRestore);
   3284 
   3285                 if (MORE_DEBUG) Slog.v(TAG, "Done consuming input tarfile, total bytes=" + mBytes);
   3286             } catch (IOException e) {
   3287                 Slog.e(TAG, "Unable to read restore input");
   3288             } finally {
   3289                 tearDownPipes();
   3290                 tearDownAgent(mTargetApp);
   3291 
   3292                 try {
   3293                     if (rawDataIn != null) rawDataIn.close();
   3294                     if (rawInStream != null) rawInStream.close();
   3295                     mInputFile.close();
   3296                 } catch (IOException e) {
   3297                     Slog.w(TAG, "Close of restore data pipe threw", e);
   3298                     /* nothing we can do about this */
   3299                 }
   3300                 synchronized (mCurrentOpLock) {
   3301                     mCurrentOperations.clear();
   3302                 }
   3303                 synchronized (mLatchObject) {
   3304                     mLatchObject.set(true);
   3305                     mLatchObject.notifyAll();
   3306                 }
   3307                 mObbConnection.tearDown();
   3308                 sendEndRestore();
   3309                 Slog.d(TAG, "Full restore pass complete.");
   3310                 mWakelock.release();
   3311             }
   3312         }
   3313 
   3314         String readHeaderLine(InputStream in) throws IOException {
   3315             int c;
   3316             StringBuilder buffer = new StringBuilder(80);
   3317             while ((c = in.read()) >= 0) {
   3318                 if (c == '\n') break;   // consume and discard the newlines
   3319                 buffer.append((char)c);
   3320             }
   3321             return buffer.toString();
   3322         }
   3323 
   3324         InputStream decodeAesHeaderAndInitialize(String encryptionName, InputStream rawInStream) {
   3325             InputStream result = null;
   3326             try {
   3327                 if (encryptionName.equals(ENCRYPTION_ALGORITHM_NAME)) {
   3328 
   3329                     String userSaltHex = readHeaderLine(rawInStream); // 5
   3330                     byte[] userSalt = hexToByteArray(userSaltHex);
   3331 
   3332                     String ckSaltHex = readHeaderLine(rawInStream); // 6
   3333                     byte[] ckSalt = hexToByteArray(ckSaltHex);
   3334 
   3335                     int rounds = Integer.parseInt(readHeaderLine(rawInStream)); // 7
   3336                     String userIvHex = readHeaderLine(rawInStream); // 8
   3337 
   3338                     String masterKeyBlobHex = readHeaderLine(rawInStream); // 9
   3339 
   3340                     // decrypt the master key blob
   3341                     Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
   3342                     SecretKey userKey = buildPasswordKey(mDecryptPassword, userSalt,
   3343                             rounds);
   3344                     byte[] IV = hexToByteArray(userIvHex);
   3345                     IvParameterSpec ivSpec = new IvParameterSpec(IV);
   3346                     c.init(Cipher.DECRYPT_MODE,
   3347                             new SecretKeySpec(userKey.getEncoded(), "AES"),
   3348                             ivSpec);
   3349                     byte[] mkCipher = hexToByteArray(masterKeyBlobHex);
   3350                     byte[] mkBlob = c.doFinal(mkCipher);
   3351 
   3352                     // first, the master key IV
   3353                     int offset = 0;
   3354                     int len = mkBlob[offset++];
   3355                     IV = Arrays.copyOfRange(mkBlob, offset, offset + len);
   3356                     offset += len;
   3357                     // then the master key itself
   3358                     len = mkBlob[offset++];
   3359                     byte[] mk = Arrays.copyOfRange(mkBlob,
   3360                             offset, offset + len);
   3361                     offset += len;
   3362                     // and finally the master key checksum hash
   3363                     len = mkBlob[offset++];
   3364                     byte[] mkChecksum = Arrays.copyOfRange(mkBlob,
   3365                             offset, offset + len);
   3366 
   3367                     // now validate the decrypted master key against the checksum
   3368                     byte[] calculatedCk = makeKeyChecksum(mk, ckSalt, rounds);
   3369                     if (Arrays.equals(calculatedCk, mkChecksum)) {
   3370                         ivSpec = new IvParameterSpec(IV);
   3371                         c.init(Cipher.DECRYPT_MODE,
   3372                                 new SecretKeySpec(mk, "AES"),
   3373                                 ivSpec);
   3374                         // Only if all of the above worked properly will 'result' be assigned
   3375                         result = new CipherInputStream(rawInStream, c);
   3376                     } else Slog.w(TAG, "Incorrect password");
   3377                 } else Slog.w(TAG, "Unsupported encryption method: " + encryptionName);
   3378             } catch (InvalidAlgorithmParameterException e) {
   3379                 Slog.e(TAG, "Needed parameter spec unavailable!", e);
   3380             } catch (BadPaddingException e) {
   3381                 // This case frequently occurs when the wrong password is used to decrypt
   3382                 // the master key.  Use the identical "incorrect password" log text as is
   3383                 // used in the checksum failure log in order to avoid providing additional
   3384                 // information to an attacker.
   3385                 Slog.w(TAG, "Incorrect password");
   3386             } catch (IllegalBlockSizeException e) {
   3387                 Slog.w(TAG, "Invalid block size in master key");
   3388             } catch (NoSuchAlgorithmException e) {
   3389                 Slog.e(TAG, "Needed decryption algorithm unavailable!");
   3390             } catch (NoSuchPaddingException e) {
   3391                 Slog.e(TAG, "Needed padding mechanism unavailable!");
   3392             } catch (InvalidKeyException e) {
   3393                 Slog.w(TAG, "Illegal password; aborting");
   3394             } catch (NumberFormatException e) {
   3395                 Slog.w(TAG, "Can't parse restore data header");
   3396             } catch (IOException e) {
   3397                 Slog.w(TAG, "Can't read input header");
   3398             }
   3399 
   3400             return result;
   3401         }
   3402 
   3403         boolean restoreOneFile(InputStream instream, byte[] buffer) {
   3404             FileMetadata info;
   3405             try {
   3406                 info = readTarHeaders(instream);
   3407                 if (info != null) {
   3408                     if (MORE_DEBUG) {
   3409                         dumpFileMetadata(info);
   3410                     }
   3411 
   3412                     final String pkg = info.packageName;
   3413                     if (!pkg.equals(mAgentPackage)) {
   3414                         // okay, change in package; set up our various
   3415                         // bookkeeping if we haven't seen it yet
   3416                         if (!mPackagePolicies.containsKey(pkg)) {
   3417                             mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
   3418                         }
   3419 
   3420                         // Clean up the previous agent relationship if necessary,
   3421                         // and let the observer know we're considering a new app.
   3422                         if (mAgent != null) {
   3423                             if (DEBUG) Slog.d(TAG, "Saw new package; tearing down old one");
   3424                             tearDownPipes();
   3425                             tearDownAgent(mTargetApp);
   3426                             mTargetApp = null;
   3427                             mAgentPackage = null;
   3428                         }
   3429                     }
   3430 
   3431                     if (info.path.equals(BACKUP_MANIFEST_FILENAME)) {
   3432                         mPackagePolicies.put(pkg, readAppManifest(info, instream));
   3433                         mPackageInstallers.put(pkg, info.installerPackageName);
   3434                         // We've read only the manifest content itself at this point,
   3435                         // so consume the footer before looping around to the next
   3436                         // input file
   3437                         skipTarPadding(info.size, instream);
   3438                         sendOnRestorePackage(pkg);
   3439                     } else {
   3440                         // Non-manifest, so it's actual file data.  Is this a package
   3441                         // we're ignoring?
   3442                         boolean okay = true;
   3443                         RestorePolicy policy = mPackagePolicies.get(pkg);
   3444                         switch (policy) {
   3445                             case IGNORE:
   3446                                 okay = false;
   3447                                 break;
   3448 
   3449                             case ACCEPT_IF_APK:
   3450                                 // If we're in accept-if-apk state, then the first file we
   3451                                 // see MUST be the apk.
   3452                                 if (info.domain.equals(FullBackup.APK_TREE_TOKEN)) {
   3453                                     if (DEBUG) Slog.d(TAG, "APK file; installing");
   3454                                     // Try to install the app.
   3455                                     String installerName = mPackageInstallers.get(pkg);
   3456                                     okay = installApk(info, installerName, instream);
   3457                                     // good to go; promote to ACCEPT
   3458                                     mPackagePolicies.put(pkg, (okay)
   3459                                             ? RestorePolicy.ACCEPT
   3460                                             : RestorePolicy.IGNORE);
   3461                                     // At this point we've consumed this file entry
   3462                                     // ourselves, so just strip the tar footer and
   3463                                     // go on to the next file in the input stream
   3464                                     skipTarPadding(info.size, instream);
   3465                                     return true;
   3466                                 } else {
   3467                                     // File data before (or without) the apk.  We can't
   3468                                     // handle it coherently in this case so ignore it.
   3469                                     mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
   3470                                     okay = false;
   3471                                 }
   3472                                 break;
   3473 
   3474                             case ACCEPT:
   3475                                 if (info.domain.equals(FullBackup.APK_TREE_TOKEN)) {
   3476                                     if (DEBUG) Slog.d(TAG, "apk present but ACCEPT");
   3477                                     // we can take the data without the apk, so we
   3478                                     // *want* to do so.  skip the apk by declaring this
   3479                                     // one file not-okay without changing the restore
   3480                                     // policy for the package.
   3481                                     okay = false;
   3482                                 }
   3483                                 break;
   3484 
   3485                             default:
   3486                                 // Something has gone dreadfully wrong when determining
   3487                                 // the restore policy from the manifest.  Ignore the
   3488                                 // rest of this package's data.
   3489                                 Slog.e(TAG, "Invalid policy from manifest");
   3490                                 okay = false;
   3491                                 mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
   3492                                 break;
   3493                         }
   3494 
   3495                         // If the policy is satisfied, go ahead and set up to pipe the
   3496                         // data to the agent.
   3497                         if (DEBUG && okay && mAgent != null) {
   3498                             Slog.i(TAG, "Reusing existing agent instance");
   3499                         }
   3500                         if (okay && mAgent == null) {
   3501                             if (DEBUG) Slog.d(TAG, "Need to launch agent for " + pkg);
   3502 
   3503                             try {
   3504                                 mTargetApp = mPackageManager.getApplicationInfo(pkg, 0);
   3505 
   3506                                 // If we haven't sent any data to this app yet, we probably
   3507                                 // need to clear it first.  Check that.
   3508                                 if (!mClearedPackages.contains(pkg)) {
   3509                                     // apps with their own backup agents are
   3510                                     // responsible for coherently managing a full
   3511                                     // restore.
   3512                                     if (mTargetApp.backupAgentName == null) {
   3513                                         if (DEBUG) Slog.d(TAG, "Clearing app data preparatory to full restore");
   3514                                         clearApplicationDataSynchronous(pkg);
   3515                                     } else {
   3516                                         if (DEBUG) Slog.d(TAG, "backup agent ("
   3517                                                 + mTargetApp.backupAgentName + ") => no clear");
   3518                                     }
   3519                                     mClearedPackages.add(pkg);
   3520                                 } else {
   3521                                     if (DEBUG) Slog.d(TAG, "We've initialized this app already; no clear required");
   3522                                 }
   3523 
   3524                                 // All set; now set up the IPC and launch the agent
   3525                                 setUpPipes();
   3526                                 mAgent = bindToAgentSynchronous(mTargetApp,
   3527                                         IApplicationThread.BACKUP_MODE_RESTORE_FULL);
   3528                                 mAgentPackage = pkg;
   3529                             } catch (IOException e) {
   3530                                 // fall through to error handling
   3531                             } catch (NameNotFoundException e) {
   3532                                 // fall through to error handling
   3533                             }
   3534 
   3535                             if (mAgent == null) {
   3536                                 if (DEBUG) Slog.d(TAG, "Unable to create agent for " + pkg);
   3537                                 okay = false;
   3538                                 tearDownPipes();
   3539                                 mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
   3540                             }
   3541                         }
   3542 
   3543                         // Sanity check: make sure we never give data to the wrong app.  This
   3544                         // should never happen but a little paranoia here won't go amiss.
   3545                         if (okay && !pkg.equals(mAgentPackage)) {
   3546                             Slog.e(TAG, "Restoring data for " + pkg
   3547                                     + " but agent is for " + mAgentPackage);
   3548                             okay = false;
   3549                         }
   3550 
   3551                         // At this point we have an agent ready to handle the full
   3552                         // restore data as well as a pipe for sending data to
   3553                         // that agent.  Tell the agent to start reading from the
   3554                         // pipe.
   3555                         if (okay) {
   3556                             boolean agentSuccess = true;
   3557                             long toCopy = info.size;
   3558                             final int token = generateToken();
   3559                             try {
   3560                                 prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL, null);
   3561                                 if (info.domain.equals(FullBackup.OBB_TREE_TOKEN)) {
   3562                                     if (DEBUG) Slog.d(TAG, "Restoring OBB file for " + pkg
   3563                                             + " : " + info.path);
   3564                                     mObbConnection.restoreObbFile(pkg, mPipes[0],
   3565                                             info.size, info.type, info.path, info.mode,
   3566                                             info.mtime, token, mBackupManagerBinder);
   3567                                 } else {
   3568                                     if (DEBUG) Slog.d(TAG, "Invoking agent to restore file "
   3569                                             + info.path);
   3570                                     // fire up the app's agent listening on the socket.  If
   3571                                     // the agent is running in the system process we can't
   3572                                     // just invoke it asynchronously, so we provide a thread
   3573                                     // for it here.
   3574                                     if (mTargetApp.processName.equals("system")) {
   3575                                         Slog.d(TAG, "system process agent - spinning a thread");
   3576                                         RestoreFileRunnable runner = new RestoreFileRunnable(
   3577                                                 mAgent, info, mPipes[0], token);
   3578                                         new Thread(runner).start();
   3579                                     } else {
   3580                                         mAgent.doRestoreFile(mPipes[0], info.size, info.type,
   3581                                                 info.domain, info.path, info.mode, info.mtime,
   3582                                                 token, mBackupManagerBinder);
   3583                                     }
   3584                                 }
   3585                             } catch (IOException e) {
   3586                                 // couldn't dup the socket for a process-local restore
   3587                                 Slog.d(TAG, "Couldn't establish restore");
   3588                                 agentSuccess = false;
   3589                                 okay = false;
   3590                             } catch (RemoteException e) {
   3591                                 // whoops, remote entity went away.  We'll eat the content
   3592                                 // ourselves, then, and not copy it over.
   3593                                 Slog.e(TAG, "Agent crashed during full restore");
   3594                                 agentSuccess = false;
   3595                                 okay = false;
   3596                             }
   3597 
   3598                             // Copy over the data if the agent is still good
   3599                             if (okay) {
   3600                                 boolean pipeOkay = true;
   3601                                 FileOutputStream pipe = new FileOutputStream(
   3602                                         mPipes[1].getFileDescriptor());
   3603                                 while (toCopy > 0) {
   3604                                     int toRead = (toCopy > buffer.length)
   3605                                     ? buffer.length : (int)toCopy;
   3606                                     int nRead = instream.read(buffer, 0, toRead);
   3607                                     if (nRead >= 0) mBytes += nRead;
   3608                                     if (nRead <= 0) break;
   3609                                     toCopy -= nRead;
   3610 
   3611                                     // send it to the output pipe as long as things
   3612                                     // are still good
   3613                                     if (pipeOkay) {
   3614                                         try {
   3615                                             pipe.write(buffer, 0, nRead);
   3616                                         } catch (IOException e) {
   3617                                             Slog.e(TAG, "Failed to write to restore pipe", e);
   3618                                             pipeOkay = false;
   3619                                         }
   3620                                     }
   3621                                 }
   3622 
   3623                                 // done sending that file!  Now we just need to consume
   3624                                 // the delta from info.size to the end of block.
   3625                                 skipTarPadding(info.size, instream);
   3626 
   3627                                 // and now that we've sent it all, wait for the remote
   3628                                 // side to acknowledge receipt
   3629                                 agentSuccess = waitUntilOperationComplete(token);
   3630                             }
   3631 
   3632                             // okay, if the remote end failed at any point, deal with
   3633                             // it by ignoring the rest of the restore on it
   3634                             if (!agentSuccess) {
   3635                                 mBackupHandler.removeMessages(MSG_TIMEOUT);
   3636                                 tearDownPipes();
   3637                                 tearDownAgent(mTargetApp);
   3638                                 mAgent = null;
   3639                                 mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
   3640                             }
   3641                         }
   3642 
   3643                         // Problems setting up the agent communication, or an already-
   3644                         // ignored package: skip to the next tar stream entry by
   3645                         // reading and discarding this file.
   3646                         if (!okay) {
   3647                             if (DEBUG) Slog.d(TAG, "[discarding file content]");
   3648                             long bytesToConsume = (info.size + 511) & ~511;
   3649                             while (bytesToConsume > 0) {
   3650                                 int toRead = (bytesToConsume > buffer.length)
   3651                                 ? buffer.length : (int)bytesToConsume;
   3652                                 long nRead = instream.read(buffer, 0, toRead);
   3653                                 if (nRead >= 0) mBytes += nRead;
   3654                                 if (nRead <= 0) break;
   3655                                 bytesToConsume -= nRead;
   3656                             }
   3657                         }
   3658                     }
   3659                 }
   3660             } catch (IOException e) {
   3661                 if (DEBUG) Slog.w(TAG, "io exception on restore socket read", e);
   3662                 // treat as EOF
   3663                 info = null;
   3664             }
   3665 
   3666             return (info != null);
   3667         }
   3668 
   3669         void setUpPipes() throws IOException {
   3670             mPipes = ParcelFileDescriptor.createPipe();
   3671         }
   3672 
   3673         void tearDownPipes() {
   3674             if (mPipes != null) {
   3675                 try {
   3676                     mPipes[0].close();
   3677                     mPipes[0] = null;
   3678                     mPipes[1].close();
   3679                     mPipes[1] = null;
   3680                 } catch (IOException e) {
   3681                     Slog.w(TAG, "Couldn't close agent pipes", e);
   3682                 }
   3683                 mPipes = null;
   3684             }
   3685         }
   3686 
   3687         void tearDownAgent(ApplicationInfo app) {
   3688             if (mAgent != null) {
   3689                 try {
   3690                     // unbind and tidy up even on timeout or failure, just in case
   3691                     mActivityManager.unbindBackupAgent(app);
   3692 
   3693                     // The agent was running with a stub Application object, so shut it down.
   3694                     // !!! We hardcode the confirmation UI's package name here rather than use a
   3695                     //     manifest flag!  TODO something less direct.
   3696                     if (app.uid != Process.SYSTEM_UID
   3697                             && !app.packageName.equals("com.android.backupconfirm")) {
   3698                         if (DEBUG) Slog.d(TAG, "Killing host process");
   3699                         mActivityManager.killApplicationProcess(app.processName, app.uid);
   3700                     } else {
   3701                         if (DEBUG) Slog.d(TAG, "Not killing after full restore");
   3702                     }
   3703                 } catch (RemoteException e) {
   3704                     Slog.d(TAG, "Lost app trying to shut down");
   3705                 }
   3706                 mAgent = null;
   3707             }
   3708         }
   3709 
   3710         class RestoreInstallObserver extends IPackageInstallObserver.Stub {
   3711             final AtomicBoolean mDone = new AtomicBoolean();
   3712             String mPackageName;
   3713             int mResult;
   3714 
   3715             public void reset() {
   3716                 synchronized (mDone) {
   3717                     mDone.set(false);
   3718                 }
   3719             }
   3720 
   3721             public void waitForCompletion() {
   3722                 synchronized (mDone) {
   3723                     while (mDone.get() == false) {
   3724                         try {
   3725                             mDone.wait();
   3726                         } catch (InterruptedException e) { }
   3727                     }
   3728                 }
   3729             }
   3730 
   3731             int getResult() {
   3732                 return mResult;
   3733             }
   3734 
   3735             @Override
   3736             public void packageInstalled(String packageName, int returnCode)
   3737                     throws RemoteException {
   3738                 synchronized (mDone) {
   3739                     mResult = returnCode;
   3740                     mPackageName = packageName;
   3741                     mDone.set(true);
   3742                     mDone.notifyAll();
   3743                 }
   3744             }
   3745         }
   3746 
   3747         class RestoreDeleteObserver extends IPackageDeleteObserver.Stub {
   3748             final AtomicBoolean mDone = new AtomicBoolean();
   3749             int mResult;
   3750 
   3751             public void reset() {
   3752                 synchronized (mDone) {
   3753                     mDone.set(false);
   3754                 }
   3755             }
   3756 
   3757             public void waitForCompletion() {
   3758                 synchronized (mDone) {
   3759                     while (mDone.get() == false) {
   3760                         try {
   3761                             mDone.wait();
   3762                         } catch (InterruptedException e) { }
   3763                     }
   3764                 }
   3765             }
   3766 
   3767             @Override
   3768             public void packageDeleted(String packageName, int returnCode) throws RemoteException {
   3769                 synchronized (mDone) {
   3770                     mResult = returnCode;
   3771                     mDone.set(true);
   3772                     mDone.notifyAll();
   3773                 }
   3774             }
   3775         }
   3776 
   3777         final RestoreInstallObserver mInstallObserver = new RestoreInstallObserver();
   3778         final RestoreDeleteObserver mDeleteObserver = new RestoreDeleteObserver();
   3779 
   3780         boolean installApk(FileMetadata info, String installerPackage, InputStream instream) {
   3781             boolean okay = true;
   3782 
   3783             if (DEBUG) Slog.d(TAG, "Installing from backup: " + info.packageName);
   3784 
   3785             // The file content is an .apk file.  Copy it out to a staging location and
   3786             // attempt to install it.
   3787             File apkFile = new File(mDataDir, info.packageName);
   3788             try {
   3789                 FileOutputStream apkStream = new FileOutputStream(apkFile);
   3790                 byte[] buffer = new byte[32 * 1024];
   3791                 long size = info.size;
   3792                 while (size > 0) {
   3793                     long toRead = (buffer.length < size) ? buffer.length : size;
   3794                     int didRead = instream.read(buffer, 0, (int)toRead);
   3795                     if (didRead >= 0) mBytes += didRead;
   3796                     apkStream.write(buffer, 0, didRead);
   3797                     size -= didRead;
   3798                 }
   3799                 apkStream.close();
   3800 
   3801                 // make sure the installer can read it
   3802                 apkFile.setReadable(true, false);
   3803 
   3804                 // Now install it
   3805                 Uri packageUri = Uri.fromFile(apkFile);
   3806                 mInstallObserver.reset();
   3807                 mPackageManager.installPackage(packageUri, mInstallObserver,
   3808                         PackageManager.INSTALL_REPLACE_EXISTING | PackageManager.INSTALL_FROM_ADB,
   3809                         installerPackage);
   3810                 mInstallObserver.waitForCompletion();
   3811 
   3812                 if (mInstallObserver.getResult() != PackageManager.INSTALL_SUCCEEDED) {
   3813                     // The only time we continue to accept install of data even if the
   3814                     // apk install failed is if we had already determined that we could
   3815                     // accept the data regardless.
   3816                     if (mPackagePolicies.get(info.packageName) != RestorePolicy.ACCEPT) {
   3817                         okay = false;
   3818                     }
   3819                 } else {
   3820                     // Okay, the install succeeded.  Make sure it was the right app.
   3821                     boolean uninstall = false;
   3822                     if (!mInstallObserver.mPackageName.equals(info.packageName)) {
   3823                         Slog.w(TAG, "Restore stream claimed to include apk for "
   3824                                 + info.packageName + " but apk was really "
   3825                                 + mInstallObserver.mPackageName);
   3826                         // delete the package we just put in place; it might be fraudulent
   3827                         okay = false;
   3828                         uninstall = true;
   3829                     } else {
   3830                         try {
   3831                             PackageInfo pkg = mPackageManager.getPackageInfo(info.packageName,
   3832                                     PackageManager.GET_SIGNATURES);
   3833                             if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) {
   3834                                 Slog.w(TAG, "Restore stream contains apk of package "
   3835                                         + info.packageName + " but it disallows backup/restore");
   3836                                 okay = false;
   3837                             } else {
   3838                                 // So far so good -- do the signatures match the manifest?
   3839                                 Signature[] sigs = mManifestSignatures.get(info.packageName);
   3840                                 if (signaturesMatch(sigs, pkg)) {
   3841                                     // If this is a system-uid app without a declared backup agent,
   3842                                     // don't restore any of the file data.
   3843                                     if ((pkg.applicationInfo.uid < Process.FIRST_APPLICATION_UID)
   3844                                             && (pkg.applicationInfo.backupAgentName == null)) {
   3845                                         Slog.w(TAG, "Installed app " + info.packageName
   3846                                                 + " has restricted uid and no agent");
   3847                                         okay = false;
   3848                                     }
   3849                                 } else {
   3850                                     Slog.w(TAG, "Installed app " + info.packageName
   3851                                             + " signatures do not match restore manifest");
   3852                                     okay = false;
   3853                                     uninstall = true;
   3854                                 }
   3855                             }
   3856                         } catch (NameNotFoundException e) {
   3857                             Slog.w(TAG, "Install of package " + info.packageName
   3858                                     + " succeeded but now not found");
   3859                             okay = false;
   3860                         }
   3861                     }
   3862 
   3863                     // If we're not okay at this point, we need to delete the package
   3864                     // that we just installed.
   3865                     if (uninstall) {
   3866                         mDeleteObserver.reset();
   3867                         mPackageManager.deletePackage(mInstallObserver.mPackageName,
   3868                                 mDeleteObserver, 0);
   3869                         mDeleteObserver.waitForCompletion();
   3870                     }
   3871                 }
   3872             } catch (IOException e) {
   3873                 Slog.e(TAG, "Unable to transcribe restored apk for install");
   3874                 okay = false;
   3875             } finally {
   3876                 apkFile.delete();
   3877             }
   3878 
   3879             return okay;
   3880         }
   3881 
   3882         // Given an actual file content size, consume the post-content padding mandated
   3883         // by the tar format.
   3884         void skipTarPadding(long size, InputStream instream) throws IOException {
   3885             long partial = (size + 512) % 512;
   3886             if (partial > 0) {
   3887                 final int needed = 512 - (int)partial;
   3888                 byte[] buffer = new byte[needed];
   3889                 if (readExactly(instream, buffer, 0, needed) == needed) {
   3890                     mBytes += needed;
   3891                 } else throw new IOException("Unexpected EOF in padding");
   3892             }
   3893         }
   3894 
   3895         // Returns a policy constant; takes a buffer arg to reduce memory churn
   3896         RestorePolicy readAppManifest(FileMetadata info, InputStream instream)
   3897                 throws IOException {
   3898             // Fail on suspiciously large manifest files
   3899             if (info.size > 64 * 1024) {
   3900                 throw new IOException("Restore manifest too big; corrupt? size=" + info.size);
   3901             }
   3902 
   3903             byte[] buffer = new byte[(int) info.size];
   3904             if (readExactly(instream, buffer, 0, (int)info.size) == info.size) {
   3905                 mBytes += info.size;
   3906             } else throw new IOException("Unexpected EOF in manifest");
   3907 
   3908             RestorePolicy policy = RestorePolicy.IGNORE;
   3909             String[] str = new String[1];
   3910             int offset = 0;
   3911 
   3912             try {
   3913                 offset = extractLine(buffer, offset, str);
   3914                 int version = Integer.parseInt(str[0]);
   3915                 if (version == BACKUP_MANIFEST_VERSION) {
   3916                     offset = extractLine(buffer, offset, str);
   3917                     String manifestPackage = str[0];
   3918                     // TODO: handle <original-package>
   3919                     if (manifestPackage.equals(info.packageName)) {
   3920                         offset = extractLine(buffer, offset, str);
   3921                         version = Integer.parseInt(str[0]);  // app version
   3922                         offset = extractLine(buffer, offset, str);
   3923                         int platformVersion = Integer.parseInt(str[0]);
   3924                         offset = extractLine(buffer, offset, str);
   3925                         info.installerPackageName = (str[0].length() > 0) ? str[0] : null;
   3926                         offset = extractLine(buffer, offset, str);
   3927                         boolean hasApk = str[0].equals("1");
   3928                         offset = extractLine(buffer, offset, str);
   3929                         int numSigs = Integer.parseInt(str[0]);
   3930                         if (numSigs > 0) {
   3931                             Signature[] sigs = new Signature[numSigs];
   3932                             for (int i = 0; i < numSigs; i++) {
   3933                                 offset = extractLine(buffer, offset, str);
   3934                                 sigs[i] = new Signature(str[0]);
   3935                             }
   3936                             mManifestSignatures.put(info.packageName, sigs);
   3937 
   3938                             // Okay, got the manifest info we need...
   3939                             try {
   3940                                 PackageInfo pkgInfo = mPackageManager.getPackageInfo(
   3941                                         info.packageName, PackageManager.GET_SIGNATURES);
   3942                                 // Fall through to IGNORE if the app explicitly disallows backup
   3943                                 final int flags = pkgInfo.applicationInfo.flags;
   3944                                 if ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0) {
   3945                                     // Restore system-uid-space packages only if they have
   3946                                     // defined a custom backup agent
   3947                                     if ((pkgInfo.applicationInfo.uid >= Process.FIRST_APPLICATION_UID)
   3948                                             || (pkgInfo.applicationInfo.backupAgentName != null)) {
   3949                                         // Verify signatures against any installed version; if they
   3950                                         // don't match, then we fall though and ignore the data.  The
   3951                                         // signatureMatch() method explicitly ignores the signature
   3952                                         // check for packages installed on the system partition, because
   3953                                         // such packages are signed with the platform cert instead of
   3954                                         // the app developer's cert, so they're different on every
   3955                                         // device.
   3956                                         if (signaturesMatch(sigs, pkgInfo)) {
   3957                                             if (pkgInfo.versionCode >= version) {
   3958                                                 Slog.i(TAG, "Sig + version match; taking data");
   3959                                                 policy = RestorePolicy.ACCEPT;
   3960                                             } else {
   3961                                                 // The data is from a newer version of the app than
   3962                                                 // is presently installed.  That means we can only
   3963                                                 // use it if the matching apk is also supplied.
   3964                                                 Slog.d(TAG, "Data version " + version
   3965                                                         + " is newer than installed version "
   3966                                                         + pkgInfo.versionCode + " - requiring apk");
   3967                                                 policy = RestorePolicy.ACCEPT_IF_APK;
   3968                                             }
   3969                                         } else {
   3970                                             Slog.w(TAG, "Restore manifest signatures do not match "
   3971                                                     + "installed application for " + info.packageName);
   3972                                         }
   3973                                     } else {
   3974                                         Slog.w(TAG, "Package " + info.packageName
   3975                                                 + " is system level with no agent");
   3976                                     }
   3977                                 } else {
   3978                                     if (DEBUG) Slog.i(TAG, "Restore manifest from "
   3979                                             + info.packageName + " but allowBackup=false");
   3980                                 }
   3981                             } catch (NameNotFoundException e) {
   3982                                 // Okay, the target app isn't installed.  We can process
   3983                                 // the restore properly only if the dataset provides the
   3984                                 // apk file and we can successfully install it.
   3985                                 if (DEBUG) Slog.i(TAG, "Package " + info.packageName
   3986                                         + " not installed; requiring apk in dataset");
   3987                                 policy = RestorePolicy.ACCEPT_IF_APK;
   3988                             }
   3989 
   3990                             if (policy == RestorePolicy.ACCEPT_IF_APK && !hasApk) {
   3991                                 Slog.i(TAG, "Cannot restore package " + info.packageName
   3992                                         + " without the matching .apk");
   3993                             }
   3994                         } else {
   3995                             Slog.i(TAG, "Missing signature on backed-up package "
   3996                                     + info.packageName);
   3997                         }
   3998                     } else {
   3999                         Slog.i(TAG, "Expected package " + info.packageName
   4000                                 + " but restore manifest claims " + manifestPackage);
   4001                     }
   4002                 } else {
   4003                     Slog.i(TAG, "Unknown restore manifest version " + version
   4004                             + " for package " + info.packageName);
   4005                 }
   4006             } catch (NumberFormatException e) {
   4007                 Slog.w(TAG, "Corrupt restore manifest for package " + info.packageName);
   4008             } catch (IllegalArgumentException e) {
   4009                 Slog.w(TAG, e.getMessage());
   4010             }
   4011 
   4012             return policy;
   4013         }
   4014 
   4015         // Builds a line from a byte buffer starting at 'offset', and returns
   4016         // the index of the next unconsumed data in the buffer.
   4017         int extractLine(byte[] buffer, int offset, String[] outStr) throws IOException {
   4018             final int end = buffer.length;
   4019             if (offset >= end) throw new IOException("Incomplete data");
   4020 
   4021             int pos;
   4022             for (pos = offset; pos < end; pos++) {
   4023                 byte c = buffer[pos];
   4024                 // at LF we declare end of line, and return the next char as the
   4025                 // starting point for the next time through
   4026                 if (c == '\n') {
   4027                     break;
   4028                 }
   4029             }
   4030             outStr[0] = new String(buffer, offset, pos - offset);
   4031             pos++;  // may be pointing an extra byte past the end but that's okay
   4032             return pos;
   4033         }
   4034 
   4035         void dumpFileMetadata(FileMetadata info) {
   4036             if (DEBUG) {
   4037                 StringBuilder b = new StringBuilder(128);
   4038 
   4039                 // mode string
   4040                 b.append((info.type == BackupAgent.TYPE_DIRECTORY) ? 'd' : '-');
   4041                 b.append(((info.mode & 0400) != 0) ? 'r' : '-');
   4042                 b.append(((info.mode & 0200) != 0) ? 'w' : '-');
   4043                 b.append(((info.mode & 0100) != 0) ? 'x' : '-');
   4044                 b.append(((info.mode & 0040) != 0) ? 'r' : '-');
   4045                 b.append(((info.mode & 0020) != 0) ? 'w' : '-');
   4046                 b.append(((info.mode & 0010) != 0) ? 'x' : '-');
   4047                 b.append(((info.mode & 0004) != 0) ? 'r' : '-');
   4048                 b.append(((info.mode & 0002) != 0) ? 'w' : '-');
   4049                 b.append(((info.mode & 0001) != 0) ? 'x' : '-');
   4050                 b.append(String.format(" %9d ", info.size));
   4051 
   4052                 Date stamp = new Date(info.mtime);
   4053                 b.append(new SimpleDateFormat("MMM dd HH:mm:ss ").format(stamp));
   4054 
   4055                 b.append(info.packageName);
   4056                 b.append(" :: ");
   4057                 b.append(info.domain);
   4058                 b.append(" :: ");
   4059                 b.append(info.path);
   4060 
   4061                 Slog.i(TAG, b.toString());
   4062             }
   4063         }
   4064         // Consume a tar file header block [sequence] and accumulate the relevant metadata
   4065         FileMetadata readTarHeaders(InputStream instream) throws IOException {
   4066             byte[] block = new byte[512];
   4067             FileMetadata info = null;
   4068 
   4069             boolean gotHeader = readTarHeader(instream, block);
   4070             if (gotHeader) {
   4071                 try {
   4072                     // okay, presume we're okay, and extract the various metadata
   4073                     info = new FileMetadata();
   4074                     info.size = extractRadix(block, 124, 12, 8);
   4075                     info.mtime = extractRadix(block, 136, 12, 8);
   4076                     info.mode = extractRadix(block, 100, 8, 8);
   4077 
   4078                     info.path = extractString(block, 345, 155); // prefix
   4079                     String path = extractString(block, 0, 100);
   4080                     if (path.length() > 0) {
   4081                         if (info.path.length() > 0) info.path += '/';
   4082                         info.path += path;
   4083                     }
   4084 
   4085                     // tar link indicator field: 1 byte at offset 156 in the header.
   4086                     int typeChar = block[156];
   4087                     if (typeChar == 'x') {
   4088                         // pax extended header, so we need to read that
   4089                         gotHeader = readPaxExtendedHeader(instream, info);
   4090                         if (gotHeader) {
   4091                             // and after a pax extended header comes another real header -- read
   4092                             // that to find the real file type
   4093                             gotHeader = readTarHeader(instream, block);
   4094                         }
   4095                         if (!gotHeader) throw new IOException("Bad or missing pax header");
   4096 
   4097                         typeChar = block[156];
   4098                     }
   4099 
   4100                     switch (typeChar) {
   4101                         case '0': info.type = BackupAgent.TYPE_FILE; break;
   4102                         case '5': {
   4103                             info.type = BackupAgent.TYPE_DIRECTORY;
   4104                             if (info.size != 0) {
   4105                                 Slog.w(TAG, "Directory entry with nonzero size in header");
   4106                                 info.size = 0;
   4107                             }
   4108                             break;
   4109                         }
   4110                         case 0: {
   4111                             // presume EOF
   4112                             if (DEBUG) Slog.w(TAG, "Saw type=0 in tar header block, info=" + info);
   4113                             return null;
   4114                         }
   4115                         default: {
   4116                             Slog.e(TAG, "Unknown tar entity type: " + typeChar);
   4117                             throw new IOException("Unknown entity type " + typeChar);
   4118                         }
   4119                     }
   4120 
   4121                     // Parse out the path
   4122                     //
   4123                     // first: apps/shared/unrecognized
   4124                     if (FullBackup.SHARED_PREFIX.regionMatches(0,
   4125                             info.path, 0, FullBackup.SHARED_PREFIX.length())) {
   4126                         // File in shared storage.  !!! TODO: implement this.
   4127                         info.path = info.path.substring(FullBackup.SHARED_PREFIX.length());
   4128                         info.packageName = SHARED_BACKUP_AGENT_PACKAGE;
   4129                         info.domain = FullBackup.SHARED_STORAGE_TOKEN;
   4130                         if (DEBUG) Slog.i(TAG, "File in shared storage: " + info.path);
   4131                     } else if (FullBackup.APPS_PREFIX.regionMatches(0,
   4132                             info.path, 0, FullBackup.APPS_PREFIX.length())) {
   4133                         // App content!  Parse out the package name and domain
   4134 
   4135                         // strip the apps/ prefix
   4136                         info.path = info.path.substring(FullBackup.APPS_PREFIX.length());
   4137 
   4138                         // extract the package name
   4139                         int slash = info.path.indexOf('/');
   4140                         if (slash < 0) throw new IOException("Illegal semantic path in " + info.path);
   4141                         info.packageName = info.path.substring(0, slash);
   4142                         info.path = info.path.substring(slash+1);
   4143 
   4144                         // if it's a manifest we're done, otherwise parse out the domains
   4145                         if (!info.path.equals(BACKUP_MANIFEST_FILENAME)) {
   4146                             slash = info.path.indexOf('/');
   4147                             if (slash < 0) throw new IOException("Illegal semantic path in non-manifest " + info.path);
   4148                             info.domain = info.path.substring(0, slash);
   4149                             info.path = info.path.substring(slash + 1);
   4150                         }
   4151                     }
   4152                 } catch (IOException e) {
   4153                     if (DEBUG) {
   4154                         Slog.e(TAG, "Parse error in header: " + e.getMessage());
   4155                         HEXLOG(block);
   4156                     }
   4157                     throw e;
   4158                 }
   4159             }
   4160             return info;
   4161         }
   4162 
   4163         private void HEXLOG(byte[] block) {
   4164             int offset = 0;
   4165             int todo = block.length;
   4166             StringBuilder buf = new StringBuilder(64);
   4167             while (todo > 0) {
   4168                 buf.append(String.format("%04x   ", offset));
   4169                 int numThisLine = (todo > 16) ? 16 : todo;
   4170                 for (int i = 0; i < numThisLine; i++) {
   4171                     buf.append(String.format("%02x ", block[offset+i]));
   4172                 }
   4173                 Slog.i("hexdump", buf.toString());
   4174                 buf.setLength(0);
   4175                 todo -= numThisLine;
   4176                 offset += numThisLine;
   4177             }
   4178         }
   4179 
   4180         // Read exactly the given number of bytes into a buffer at the stated offset.
   4181         // Returns false if EOF is encountered before the requested number of bytes
   4182         // could be read.
   4183         int readExactly(InputStream in, byte[] buffer, int offset, int size)
   4184                 throws IOException {
   4185             if (size <= 0) throw new IllegalArgumentException("size must be > 0");
   4186 
   4187             int soFar = 0;
   4188             while (soFar < size) {
   4189                 int nRead = in.read(buffer, offset + soFar, size - soFar);
   4190                 if (nRead <= 0) {
   4191                     if (MORE_DEBUG) Slog.w(TAG, "- wanted exactly " + size + " but got only " + soFar);
   4192                     break;
   4193                 }
   4194                 soFar += nRead;
   4195             }
   4196             return soFar;
   4197         }
   4198 
   4199         boolean readTarHeader(InputStream instream, byte[] block) throws IOException {
   4200             final int got = readExactly(instream, block, 0, 512);
   4201             if (got == 0) return false;     // Clean EOF
   4202             if (got < 512) throw new IOException("Unable to read full block header");
   4203             mBytes += 512;
   4204             return true;
   4205         }
   4206 
   4207         // overwrites 'info' fields based on the pax extended header
   4208         boolean readPaxExtendedHeader(InputStream instream, FileMetadata info)
   4209                 throws IOException {
   4210             // We should never see a pax extended header larger than this
   4211             if (info.size > 32*1024) {
   4212                 Slog.w(TAG, "Suspiciously large pax header size " + info.size
   4213                         + " - aborting");
   4214                 throw new IOException("Sanity failure: pax header size " + info.size);
   4215             }
   4216 
   4217             // read whole blocks, not just the content size
   4218             int numBlocks = (int)((info.size + 511) >> 9);
   4219             byte[] data = new byte[numBlocks * 512];
   4220             if (readExactly(instream, data, 0, data.length) < data.length) {
   4221                 throw new IOException("Unable to read full pax header");
   4222             }
   4223             mBytes += data.length;
   4224 
   4225             final int contentSize = (int) info.size;
   4226             int offset = 0;
   4227             do {
   4228                 // extract the line at 'offset'
   4229                 int eol = offset+1;
   4230                 while (eol < contentSize && data[eol] != ' ') eol++;
   4231                 if (eol >= contentSize) {
   4232                     // error: we just hit EOD looking for the end of the size field
   4233                     throw new IOException("Invalid pax data");
   4234                 }
   4235                 // eol points to the space between the count and the key
   4236                 int linelen = (int) extractRadix(data, offset, eol - offset, 10);
   4237                 int key = eol + 1;  // start of key=value
   4238                 eol = offset + linelen - 1; // trailing LF
   4239                 int value;
   4240                 for (value = key+1; data[value] != '=' && value <= eol; value++);
   4241                 if (value > eol) {
   4242                     throw new IOException("Invalid pax declaration");
   4243                 }
   4244 
   4245                 // pax requires that key/value strings be in UTF-8
   4246                 String keyStr = new String(data, key, value-key, "UTF-8");
   4247                 // -1 to strip the trailing LF
   4248                 String valStr = new String(data, value+1, eol-value-1, "UTF-8");
   4249 
   4250                 if ("path".equals(keyStr)) {
   4251                     info.path = valStr;
   4252                 } else if ("size".equals(keyStr)) {
   4253                     info.size = Long.parseLong(valStr);
   4254                 } else {
   4255                     if (DEBUG) Slog.i(TAG, "Unhandled pax key: " + key);
   4256                 }
   4257 
   4258                 offset += linelen;
   4259             } while (offset < contentSize);
   4260 
   4261             return true;
   4262         }
   4263 
   4264         long extractRadix(byte[] data, int offset, int maxChars, int radix)
   4265                 throws IOException {
   4266             long value = 0;
   4267             final int end = offset + maxChars;
   4268             for (int i = offset; i < end; i++) {
   4269                 final byte b = data[i];
   4270                 // Numeric fields in tar can terminate with either NUL or SPC
   4271                 if (b == 0 || b == ' ') break;
   4272                 if (b < '0' || b > ('0' + radix - 1)) {
   4273                     throw new IOException("Invalid number in header: '" + (char)b + "' for radix " + radix);
   4274                 }
   4275                 value = radix * value + (b - '0');
   4276             }
   4277             return value;
   4278         }
   4279 
   4280         String extractString(byte[] data, int offset, int maxChars) throws IOException {
   4281             final int end = offset + maxChars;
   4282             int eos = offset;
   4283             // tar string fields terminate early with a NUL
   4284             while (eos < end && data[eos] != 0) eos++;
   4285             return new String(data, offset, eos-offset, "US-ASCII");
   4286         }
   4287 
   4288         void sendStartRestore() {
   4289             if (mObserver != null) {
   4290                 try {
   4291                     mObserver.onStartRestore();
   4292                 } catch (RemoteException e) {
   4293                     Slog.w(TAG, "full restore observer went away: startRestore");
   4294                     mObserver = null;
   4295                 }
   4296             }
   4297         }
   4298 
   4299         void sendOnRestorePackage(String name) {
   4300             if (mObserver != null) {
   4301                 try {
   4302                     // TODO: use a more user-friendly name string
   4303                     mObserver.onRestorePackage(name);
   4304                 } catch (RemoteException e) {
   4305                     Slog.w(TAG, "full restore observer went away: restorePackage");
   4306                     mObserver = null;
   4307                 }
   4308             }
   4309         }
   4310 
   4311         void sendEndRestore() {
   4312             if (mObserver != null) {
   4313                 try {
   4314                     mObserver.onEndRestore();
   4315                 } catch (RemoteException e) {
   4316                     Slog.w(TAG, "full restore observer went away: endRestore");
   4317                     mObserver = null;
   4318                 }
   4319             }
   4320         }
   4321     }
   4322 
   4323     // ----- Restore handling -----
   4324 
   4325     private boolean signaturesMatch(Signature[] storedSigs, PackageInfo target) {
   4326         // If the target resides on the system partition, we allow it to restore
   4327         // data from the like-named package in a restore set even if the signatures
   4328         // do not match.  (Unlike general applications, those flashed to the system
   4329         // partition will be signed with the device's platform certificate, so on
   4330         // different phones the same system app will have different signatures.)
   4331         if ((target.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
   4332             if (DEBUG) Slog.v(TAG, "System app " + target.packageName + " - skipping sig check");
   4333             return true;
   4334         }
   4335 
   4336         // Allow unsigned apps, but not signed on one device and unsigned on the other
   4337         // !!! TODO: is this the right policy?
   4338         Signature[] deviceSigs = target.signatures;
   4339         if (MORE_DEBUG) Slog.v(TAG, "signaturesMatch(): stored=" + storedSigs
   4340                 + " device=" + deviceSigs);
   4341         if ((storedSigs == null || storedSigs.length == 0)
   4342                 && (deviceSigs == null || deviceSigs.length == 0)) {
   4343             return true;
   4344         }
   4345         if (storedSigs == null || deviceSigs == null) {
   4346             return false;
   4347         }
   4348 
   4349         // !!! TODO: this demands that every stored signature match one
   4350         // that is present on device, and does not demand the converse.
   4351         // Is this this right policy?
   4352         int nStored = storedSigs.length;
   4353         int nDevice = deviceSigs.length;
   4354 
   4355         for (int i=0; i < nStored; i++) {
   4356             boolean match = false;
   4357             for (int j=0; j < nDevice; j++) {
   4358                 if (storedSigs[i].equals(deviceSigs[j])) {
   4359                     match = true;
   4360                     break;
   4361                 }
   4362             }
   4363             if (!match) {
   4364                 return false;
   4365             }
   4366         }
   4367         return true;
   4368     }
   4369 
   4370     enum RestoreState {
   4371         INITIAL,
   4372         DOWNLOAD_DATA,
   4373         PM_METADATA,
   4374         RUNNING_QUEUE,
   4375         FINAL
   4376     }
   4377 
   4378     class PerformRestoreTask implements BackupRestoreTask {
   4379         private IBackupTransport mTransport;
   4380         private IRestoreObserver mObserver;
   4381         private long mToken;
   4382         private PackageInfo mTargetPackage;
   4383         private File mStateDir;
   4384         private int mPmToken;
   4385         private boolean mNeedFullBackup;
   4386         private HashSet<String> mFilterSet;
   4387         private long mStartRealtime;
   4388         private PackageManagerBackupAgent mPmAgent;
   4389         private List<PackageInfo> mAgentPackages;
   4390         private ArrayList<PackageInfo> mRestorePackages;
   4391         private RestoreState mCurrentState;
   4392         private int mCount;
   4393         private boolean mFinished;
   4394         private int mStatus;
   4395         private File mBackupDataName;
   4396         private File mNewStateName;
   4397         private File mSavedStateName;
   4398         private ParcelFileDescriptor mBackupData;
   4399         private ParcelFileDescriptor mNewState;
   4400         private PackageInfo mCurrentPackage;
   4401 
   4402 
   4403         class RestoreRequest {
   4404             public PackageInfo app;
   4405             public int storedAppVersion;
   4406 
   4407             RestoreRequest(PackageInfo _app, int _version) {
   4408                 app = _app;
   4409                 storedAppVersion = _version;
   4410             }
   4411         }
   4412 
   4413         PerformRestoreTask(IBackupTransport transport, String dirName, IRestoreObserver observer,
   4414                 long restoreSetToken, PackageInfo targetPackage, int pmToken,
   4415                 boolean needFullBackup, String[] filterSet) {
   4416             mCurrentState = RestoreState.INITIAL;
   4417             mFinished = false;
   4418             mPmAgent = null;
   4419 
   4420             mTransport = transport;
   4421             mObserver = observer;
   4422             mToken = restoreSetToken;
   4423             mTargetPackage = targetPackage;
   4424             mPmToken = pmToken;
   4425             mNeedFullBackup = needFullBackup;
   4426 
   4427             if (filterSet != null) {
   4428                 mFilterSet = new HashSet<String>();
   4429                 for (String pkg : filterSet) {
   4430                     mFilterSet.add(pkg);
   4431                 }
   4432             } else {
   4433                 mFilterSet = null;
   4434             }
   4435 
   4436             mStateDir = new File(mBaseStateDir, dirName);
   4437         }
   4438 
   4439         // Execute one tick of whatever state machine the task implements
   4440         @Override
   4441         public void execute() {
   4442             if (MORE_DEBUG) Slog.v(TAG, "*** Executing restore step: " + mCurrentState);
   4443             switch (mCurrentState) {
   4444                 case INITIAL:
   4445                     beginRestore();
   4446                     break;
   4447 
   4448                 case DOWNLOAD_DATA:
   4449                     downloadRestoreData();
   4450                     break;
   4451 
   4452                 case PM_METADATA:
   4453                     restorePmMetadata();
   4454                     break;
   4455 
   4456                 case RUNNING_QUEUE:
   4457                     restoreNextAgent();
   4458                     break;
   4459 
   4460                 case FINAL:
   4461                     if (!mFinished) finalizeRestore();
   4462                     else {
   4463                         Slog.e(TAG, "Duplicate finish");
   4464                     }
   4465                     mFinished = true;
   4466                     break;
   4467             }
   4468         }
   4469 
   4470         // Initialize and set up for the PM metadata restore, which comes first
   4471         void beginRestore() {
   4472             // Don't account time doing the restore as inactivity of the app
   4473             // that has opened a restore session.
   4474             mBackupHandler.removeMessages(MSG_RESTORE_TIMEOUT);
   4475 
   4476             // Assume error until we successfully init everything
   4477             mStatus = BackupConstants.TRANSPORT_ERROR;
   4478 
   4479             try {
   4480                 // TODO: Log this before getAvailableRestoreSets, somehow
   4481                 EventLog.writeEvent(EventLogTags.RESTORE_START, mTransport.transportDirName(), mToken);
   4482 
   4483                 // Get the list of all packages which have backup enabled.
   4484                 // (Include the Package Manager metadata pseudo-package first.)
   4485                 mRestorePackages = new ArrayList<PackageInfo>();
   4486                 PackageInfo omPackage = new PackageInfo();
   4487                 omPackage.packageName = PACKAGE_MANAGER_SENTINEL;
   4488                 mRestorePackages.add(omPackage);
   4489 
   4490                 mAgentPackages = allAgentPackages();
   4491                 if (mTargetPackage == null) {
   4492                     // if there's a filter set, strip out anything that isn't
   4493                     // present before proceeding
   4494                     if (mFilterSet != null) {
   4495                         for (int i = mAgentPackages.size() - 1; i >= 0; i--) {
   4496                             final PackageInfo pkg = mAgentPackages.get(i);
   4497                             if (! mFilterSet.contains(pkg.packageName)) {
   4498                                 mAgentPackages.remove(i);
   4499                             }
   4500                         }
   4501                         if (MORE_DEBUG) {
   4502                             Slog.i(TAG, "Post-filter package set for restore:");
   4503                             for (PackageInfo p : mAgentPackages) {
   4504                                 Slog.i(TAG, "    " + p);
   4505                             }
   4506                         }
   4507                     }
   4508                     mRestorePackages.addAll(mAgentPackages);
   4509                 } else {
   4510                     // Just one package to attempt restore of
   4511                     mRestorePackages.add(mTargetPackage);
   4512                 }
   4513 
   4514                 // let the observer know that we're running
   4515                 if (mObserver != null) {
   4516                     try {
   4517                         // !!! TODO: get an actual count from the transport after
   4518                         // its startRestore() runs?
   4519                         mObserver.restoreStarting(mRestorePackages.size());
   4520                     } catch (RemoteException e) {
   4521                         Slog.d(TAG, "Restore observer died at restoreStarting");
   4522                         mObserver = null;
   4523                     }
   4524                 }
   4525             } catch (RemoteException e) {
   4526                 // Something has gone catastrophically wrong with the transport
   4527                 Slog.e(TAG, "Error communicating with transport for restore");
   4528                 executeNextState(RestoreState.FINAL);
   4529                 return;
   4530             }
   4531 
   4532             mStatus = BackupConstants.TRANSPORT_OK;
   4533             executeNextState(RestoreState.DOWNLOAD_DATA);
   4534         }
   4535 
   4536         void downloadRestoreData() {
   4537             // Note that the download phase can be very time consuming, but we're executing
   4538             // it inline here on the looper.  This is "okay" because it is not calling out to
   4539             // third party code; the transport is "trusted," and so we assume it is being a
   4540             // good citizen and timing out etc when appropriate.
   4541             //
   4542             // TODO: when appropriate, move the download off the looper and rearrange the
   4543             //       error handling around that.
   4544             try {
   4545                 mStatus = mTransport.startRestore(mToken,
   4546                         mRestorePackages.toArray(new PackageInfo[0]));
   4547                 if (mStatus != BackupConstants.TRANSPORT_OK) {
   4548                     Slog.e(TAG, "Error starting restore operation");
   4549                     EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
   4550                     executeNextState(RestoreState.FINAL);
   4551                     return;
   4552                 }
   4553             } catch (RemoteException e) {
   4554                 Slog.e(TAG, "Error communicating with transport for restore");
   4555                 EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
   4556                 mStatus = BackupConstants.TRANSPORT_ERROR;
   4557                 executeNextState(RestoreState.FINAL);
   4558                 return;
   4559             }
   4560 
   4561             // Successful download of the data to be parceled out to the apps, so off we go.
   4562             executeNextState(RestoreState.PM_METADATA);
   4563         }
   4564 
   4565         void restorePmMetadata() {
   4566             try {
   4567                 String packageName = mTransport.nextRestorePackage();
   4568                 if (packageName == null) {
   4569                     Slog.e(TAG, "Error getting first restore package");
   4570                     EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
   4571                     mStatus = BackupConstants.TRANSPORT_ERROR;
   4572                     executeNextState(RestoreState.FINAL);
   4573                     return;
   4574                 } else if (packageName.equals("")) {
   4575                     Slog.i(TAG, "No restore data available");
   4576                     int millis = (int) (SystemClock.elapsedRealtime() - mStartRealtime);
   4577                     EventLog.writeEvent(EventLogTags.RESTORE_SUCCESS, 0, millis);
   4578                     mStatus = BackupConstants.TRANSPORT_OK;
   4579                     executeNextState(RestoreState.FINAL);
   4580                     return;
   4581                 } else if (!packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
   4582                     Slog.e(TAG, "Expected restore data for \"" + PACKAGE_MANAGER_SENTINEL
   4583                             + "\", found only \"" + packageName + "\"");
   4584                     EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, PACKAGE_MANAGER_SENTINEL,
   4585                             "Package manager data missing");
   4586                     executeNextState(RestoreState.FINAL);
   4587                     return;
   4588                 }
   4589 
   4590                 // Pull the Package Manager metadata from the restore set first
   4591                 PackageInfo omPackage = new PackageInfo();
   4592                 omPackage.packageName = PACKAGE_MANAGER_SENTINEL;
   4593                 mPmAgent = new PackageManagerBackupAgent(
   4594                         mPackageManager, mAgentPackages);
   4595                 initiateOneRestore(omPackage, 0, IBackupAgent.Stub.asInterface(mPmAgent.onBind()),
   4596                         mNeedFullBackup);
   4597                 // The PM agent called operationComplete() already, because our invocation
   4598                 // of it is process-local and therefore synchronous.  That means that a
   4599                 // RUNNING_QUEUE message is already enqueued.  Only if we're unable to
   4600                 // proceed with running the queue do we remove that pending message and
   4601                 // jump straight to the FINAL state.
   4602 
   4603                 // Verify that the backup set includes metadata.  If not, we can't do
   4604                 // signature/version verification etc, so we simply do not proceed with
   4605                 // the restore operation.
   4606                 if (!mPmAgent.hasMetadata()) {
   4607                     Slog.e(TAG, "No restore metadata available, so not restoring settings");
   4608                     EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, PACKAGE_MANAGER_SENTINEL,
   4609                     "Package manager restore metadata missing");
   4610                     mStatus = BackupConstants.TRANSPORT_ERROR;
   4611                     mBackupHandler.removeMessages(MSG_BACKUP_RESTORE_STEP, this);
   4612                     executeNextState(RestoreState.FINAL);
   4613                     return;
   4614                 }
   4615             } catch (RemoteException e) {
   4616                 Slog.e(TAG, "Error communicating with transport for restore");
   4617                 EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
   4618                 mStatus = BackupConstants.TRANSPORT_ERROR;
   4619                 mBackupHandler.removeMessages(MSG_BACKUP_RESTORE_STEP, this);
   4620                 executeNextState(RestoreState.FINAL);
   4621                 return;
   4622             }
   4623 
   4624             // Metadata is intact, so we can now run the restore queue.  If we get here,
   4625             // we have already enqueued the necessary next-step message on the looper.
   4626         }
   4627 
   4628         void restoreNextAgent() {
   4629             try {
   4630                 String packageName = mTransport.nextRestorePackage();
   4631 
   4632                 if (packageName == null) {
   4633                     Slog.e(TAG, "Error getting next restore package");
   4634                     EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
   4635                     executeNextState(RestoreState.FINAL);
   4636                     return;
   4637                 } else if (packageName.equals("")) {
   4638                     if (DEBUG) Slog.v(TAG, "No next package, finishing restore");
   4639                     int millis = (int) (SystemClock.elapsedRealtime() - mStartRealtime);
   4640                     EventLog.writeEvent(EventLogTags.RESTORE_SUCCESS, mCount, millis);
   4641                     executeNextState(RestoreState.FINAL);
   4642                     return;
   4643                 }
   4644 
   4645                 if (mObserver != null) {
   4646                     try {
   4647                         mObserver.onUpdate(mCount, packageName);
   4648                     } catch (RemoteException e) {
   4649                         Slog.d(TAG, "Restore observer died in onUpdate");
   4650                         mObserver = null;
   4651                     }
   4652                 }
   4653 
   4654                 Metadata metaInfo = mPmAgent.getRestoredMetadata(packageName);
   4655                 if (metaInfo == null) {
   4656                     Slog.e(TAG, "Missing metadata for " + packageName);
   4657                     EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
   4658                             "Package metadata missing");
   4659                     executeNextState(RestoreState.RUNNING_QUEUE);
   4660                     return;
   4661                 }
   4662 
   4663                 PackageInfo packageInfo;
   4664                 try {
   4665                     int flags = PackageManager.GET_SIGNATURES;
   4666                     packageInfo = mPackageManager.getPackageInfo(packageName, flags);
   4667                 } catch (NameNotFoundException e) {
   4668                     Slog.e(TAG, "Invalid package restoring data", e);
   4669                     EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
   4670                             "Package missing on device");
   4671                     executeNextState(RestoreState.RUNNING_QUEUE);
   4672                     return;
   4673                 }
   4674 
   4675                 if (packageInfo.applicationInfo.backupAgentName == null
   4676                         || "".equals(packageInfo.applicationInfo.backupAgentName)) {
   4677                     if (DEBUG) {
   4678                         Slog.i(TAG, "Data exists for package " + packageName
   4679                                 + " but app has no agent; skipping");
   4680                     }
   4681                     EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
   4682                             "Package has no agent");
   4683                     executeNextState(RestoreState.RUNNING_QUEUE);
   4684                     return;
   4685                 }
   4686 
   4687                 if (metaInfo.versionCode > packageInfo.versionCode) {
   4688                     // Data is from a "newer" version of the app than we have currently
   4689                     // installed.  If the app has not declared that it is prepared to
   4690                     // handle this case, we do not attempt the restore.
   4691                     if ((packageInfo.applicationInfo.flags
   4692                             & ApplicationInfo.FLAG_RESTORE_ANY_VERSION) == 0) {
   4693                         String message = "Version " + metaInfo.versionCode
   4694                         + " > installed version " + packageInfo.versionCode;
   4695                         Slog.w(TAG, "Package " + packageName + ": " + message);
   4696                         EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
   4697                                 packageName, message);
   4698                         executeNextState(RestoreState.RUNNING_QUEUE);
   4699                         return;
   4700                     } else {
   4701                         if (DEBUG) Slog.v(TAG, "Version " + metaInfo.versionCode
   4702                                 + " > installed " + packageInfo.versionCode
   4703                                 + " but restoreAnyVersion");
   4704                     }
   4705                 }
   4706 
   4707                 if (!signaturesMatch(metaInfo.signatures, packageInfo)) {
   4708                     Slog.w(TAG, "Signature mismatch restoring " + packageName);
   4709                     EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
   4710                             "Signature mismatch");
   4711                     executeNextState(RestoreState.RUNNING_QUEUE);
   4712                     return;
   4713                 }
   4714 
   4715                 if (DEBUG) Slog.v(TAG, "Package " + packageName
   4716                         + " restore version [" + metaInfo.versionCode
   4717                         + "] is compatible with installed version ["
   4718                         + packageInfo.versionCode + "]");
   4719 
   4720                 // Then set up and bind the agent
   4721                 IBackupAgent agent = bindToAgentSynchronous(
   4722                         packageInfo.applicationInfo,
   4723                         IApplicationThread.BACKUP_MODE_INCREMENTAL);
   4724                 if (agent == null) {
   4725                     Slog.w(TAG, "Can't find backup agent for " + packageName);
   4726                     EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
   4727                             "Restore agent missing");
   4728                     executeNextState(RestoreState.RUNNING_QUEUE);
   4729                     return;
   4730                 }
   4731 
   4732                 // And then finally start the restore on this agent
   4733                 try {
   4734                     initiateOneRestore(packageInfo, metaInfo.versionCode, agent, mNeedFullBackup);
   4735                     ++mCount;
   4736                 } catch (Exception e) {
   4737                     Slog.e(TAG, "Error when attempting restore: " + e.toString());
   4738                     agentErrorCleanup();
   4739                     executeNextState(RestoreState.RUNNING_QUEUE);
   4740                 }
   4741             } catch (RemoteException e) {
   4742                 Slog.e(TAG, "Unable to fetch restore data from transport");
   4743                 mStatus = BackupConstants.TRANSPORT_ERROR;
   4744                 executeNextState(RestoreState.FINAL);
   4745             }
   4746         }
   4747 
   4748         void finalizeRestore() {
   4749             if (MORE_DEBUG) Slog.d(TAG, "finishing restore mObserver=" + mObserver);
   4750 
   4751             try {
   4752                 mTransport.finishRestore();
   4753             } catch (RemoteException e) {
   4754                 Slog.e(TAG, "Error finishing restore", e);
   4755             }
   4756 
   4757             if (mObserver != null) {
   4758                 try {
   4759                     mObserver.restoreFinished(mStatus);
   4760                 } catch (RemoteException e) {
   4761                     Slog.d(TAG, "Restore observer died at restoreFinished");
   4762                 }
   4763             }
   4764 
   4765             // If this was a restoreAll operation, record that this was our
   4766             // ancestral dataset, as well as the set of apps that are possibly
   4767             // restoreable from the dataset
   4768             if (mTargetPackage == null && mPmAgent != null) {
   4769                 mAncestralPackages = mPmAgent.getRestoredPackages();
   4770                 mAncestralToken = mToken;
   4771                 writeRestoreTokens();
   4772             }
   4773 
   4774             // We must under all circumstances tell the Package Manager to
   4775             // proceed with install notifications if it's waiting for us.
   4776             if (mPmToken > 0) {
   4777                 if (MORE_DEBUG) Slog.v(TAG, "finishing PM token " + mPmToken);
   4778                 try {
   4779                     mPackageManagerBinder.finishPackageInstall(mPmToken);
   4780                 } catch (RemoteException e) { /* can't happen */ }
   4781             }
   4782 
   4783             // Furthermore we need to reset the session timeout clock
   4784             mBackupHandler.removeMessages(MSG_RESTORE_TIMEOUT);
   4785             mBackupHandler.sendEmptyMessageDelayed(MSG_RESTORE_TIMEOUT,
   4786                     TIMEOUT_RESTORE_INTERVAL);
   4787 
   4788             // done; we can finally release the wakelock
   4789             Slog.i(TAG, "Restore complete.");
   4790             mWakelock.release();
   4791         }
   4792 
   4793         // Call asynchronously into the app, passing it the restore data.  The next step
   4794         // after this is always a callback, either operationComplete() or handleTimeout().
   4795         void initiateOneRestore(PackageInfo app, int appVersionCode, IBackupAgent agent,
   4796                 boolean needFullBackup) {
   4797             mCurrentPackage = app;
   4798             final String packageName = app.packageName;
   4799 
   4800             if (DEBUG) Slog.d(TAG, "initiateOneRestore packageName=" + packageName);
   4801 
   4802             // !!! TODO: get the dirs from the transport
   4803             mBackupDataName = new File(mDataDir, packageName + ".restore");
   4804             mNewStateName = new File(mStateDir, packageName + ".new");
   4805             mSavedStateName = new File(mStateDir, packageName);
   4806 
   4807             final int token = generateToken();
   4808             try {
   4809                 // Run the transport's restore pass
   4810                 mBackupData = ParcelFileDescriptor.open(mBackupDataName,
   4811                             ParcelFileDescriptor.MODE_READ_WRITE |
   4812                             ParcelFileDescriptor.MODE_CREATE |
   4813                             ParcelFileDescriptor.MODE_TRUNCATE);
   4814 
   4815                 if (!SELinux.restorecon(mBackupDataName)) {
   4816                     Slog.e(TAG, "SElinux restorecon failed for " + mBackupDataName);
   4817                 }
   4818 
   4819                 if (mTransport.getRestoreData(mBackupData) != BackupConstants.TRANSPORT_OK) {
   4820                     // Transport-level failure, so we wind everything up and
   4821                     // terminate the restore operation.
   4822                     Slog.e(TAG, "Error getting restore data for " + packageName);
   4823                     EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
   4824                     mBackupData.close();
   4825                     mBackupDataName.delete();
   4826                     executeNextState(RestoreState.FINAL);
   4827                     return;
   4828                 }
   4829 
   4830                 // Okay, we have the data.  Now have the agent do the restore.
   4831                 mBackupData.close();
   4832                 mBackupData = ParcelFileDescriptor.open(mBackupDataName,
   4833                             ParcelFileDescriptor.MODE_READ_ONLY);
   4834 
   4835                 mNewState = ParcelFileDescriptor.open(mNewStateName,
   4836                             ParcelFileDescriptor.MODE_READ_WRITE |
   4837                             ParcelFileDescriptor.MODE_CREATE |
   4838                             ParcelFileDescriptor.MODE_TRUNCATE);
   4839 
   4840                 // Kick off the restore, checking for hung agents
   4841                 prepareOperationTimeout(token, TIMEOUT_RESTORE_INTERVAL, this);
   4842                 agent.doRestore(mBackupData, appVersionCode, mNewState, token, mBackupManagerBinder);
   4843             } catch (Exception e) {
   4844                 Slog.e(TAG, "Unable to call app for restore: " + packageName, e);
   4845                 EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName, e.toString());
   4846                 agentErrorCleanup();    // clears any pending timeout messages as well
   4847 
   4848                 // After a restore failure we go back to running the queue.  If there
   4849                 // are no more packages to be restored that will be handled by the
   4850                 // next step.
   4851                 executeNextState(RestoreState.RUNNING_QUEUE);
   4852             }
   4853         }
   4854 
   4855         void agentErrorCleanup() {
   4856             // If the agent fails restore, it might have put the app's data
   4857             // into an incoherent state.  For consistency we wipe its data
   4858             // again in this case before continuing with normal teardown
   4859             clearApplicationDataSynchronous(mCurrentPackage.packageName);
   4860             agentCleanup();
   4861         }
   4862 
   4863         void agentCleanup() {
   4864             mBackupDataName.delete();
   4865             try { if (mBackupData != null) mBackupData.close(); } catch (IOException e) {}
   4866             try { if (mNewState != null) mNewState.close(); } catch (IOException e) {}
   4867             mBackupData = mNewState = null;
   4868 
   4869             // if everything went okay, remember the recorded state now
   4870             //
   4871             // !!! TODO: the restored data should be migrated on the server
   4872             // side into the current dataset.  In that case the new state file
   4873             // we just created would reflect the data already extant in the
   4874             // backend, so there'd be nothing more to do.  Until that happens,
   4875             // however, we need to make sure that we record the data to the
   4876             // current backend dataset.  (Yes, this means shipping the data over
   4877             // the wire in both directions.  That's bad, but consistency comes
   4878             // first, then efficiency.)  Once we introduce server-side data
   4879             // migration to the newly-restored device's dataset, we will change
   4880             // the following from a discard of the newly-written state to the
   4881             // "correct" operation of renaming into the canonical state blob.
   4882             mNewStateName.delete();                      // TODO: remove; see above comment
   4883             //mNewStateName.renameTo(mSavedStateName);   // TODO: replace with this
   4884 
   4885             // If this wasn't the PM pseudopackage, tear down the agent side
   4886             if (mCurrentPackage.applicationInfo != null) {
   4887                 // unbind and tidy up even on timeout or failure
   4888                 try {
   4889                     mActivityManager.unbindBackupAgent(mCurrentPackage.applicationInfo);
   4890 
   4891                     // The agent was probably running with a stub Application object,
   4892                     // which isn't a valid run mode for the main app logic.  Shut
   4893                     // down the app so that next time it's launched, it gets the
   4894                     // usual full initialization.  Note that this is only done for
   4895                     // full-system restores: when a single app has requested a restore,
   4896                     // it is explicitly not killed following that operation.
   4897                     if (mTargetPackage == null && (mCurrentPackage.applicationInfo.flags
   4898                             & ApplicationInfo.FLAG_KILL_AFTER_RESTORE) != 0) {
   4899                         if (DEBUG) Slog.d(TAG, "Restore complete, killing host process of "
   4900                                 + mCurrentPackage.applicationInfo.processName);
   4901                         mActivityManager.killApplicationProcess(
   4902                                 mCurrentPackage.applicationInfo.processName,
   4903                                 mCurrentPackage.applicationInfo.uid);
   4904                     }
   4905                 } catch (RemoteException e) {
   4906                     // can't happen; we run in the same process as the activity manager
   4907                 }
   4908             }
   4909 
   4910             // The caller is responsible for reestablishing the state machine; our
   4911             // responsibility here is to clear the decks for whatever comes next.
   4912             mBackupHandler.removeMessages(MSG_TIMEOUT, this);
   4913             synchronized (mCurrentOpLock) {
   4914                 mCurrentOperations.clear();
   4915             }
   4916         }
   4917 
   4918         // A call to agent.doRestore() has been positively acknowledged as complete
   4919         @Override
   4920         public void operationComplete() {
   4921             int size = (int) mBackupDataName.length();
   4922             EventLog.writeEvent(EventLogTags.RESTORE_PACKAGE, mCurrentPackage.packageName, size);
   4923             // Just go back to running the restore queue
   4924             agentCleanup();
   4925 
   4926             executeNextState(RestoreState.RUNNING_QUEUE);
   4927         }
   4928 
   4929         // A call to agent.doRestore() has timed out
   4930         @Override
   4931         public void handleTimeout() {
   4932             Slog.e(TAG, "Timeout restoring application " + mCurrentPackage.packageName);
   4933             EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
   4934                     mCurrentPackage.packageName, "restore timeout");
   4935             // Handle like an agent that threw on invocation: wipe it and go on to the next
   4936             agentErrorCleanup();
   4937             executeNextState(RestoreState.RUNNING_QUEUE);
   4938         }
   4939 
   4940         void executeNextState(RestoreState nextState) {
   4941             if (MORE_DEBUG) Slog.i(TAG, " => executing next step on "
   4942                     + this + " nextState=" + nextState);
   4943             mCurrentState = nextState;
   4944             Message msg = mBackupHandler.obtainMessage(MSG_BACKUP_RESTORE_STEP, this);
   4945             mBackupHandler.sendMessage(msg);
   4946         }
   4947     }
   4948 
   4949     class PerformClearTask implements Runnable {
   4950         IBackupTransport mTransport;
   4951         PackageInfo mPackage;
   4952 
   4953         PerformClearTask(IBackupTransport transport, PackageInfo packageInfo) {
   4954             mTransport = transport;
   4955             mPackage = packageInfo;
   4956         }
   4957 
   4958         public void run() {
   4959             try {
   4960                 // Clear the on-device backup state to ensure a full backup next time
   4961                 File stateDir = new File(mBaseStateDir, mTransport.transportDirName());
   4962                 File stateFile = new File(stateDir, mPackage.packageName);
   4963                 stateFile.delete();
   4964 
   4965                 // Tell the transport to remove all the persistent storage for the app
   4966                 // TODO - need to handle failures
   4967                 mTransport.clearBackupData(mPackage);
   4968             } catch (RemoteException e) {
   4969                 // can't happen; the transport is local
   4970             } catch (Exception e) {
   4971                 Slog.e(TAG, "Transport threw attempting to clear data for " + mPackage);
   4972             } finally {
   4973                 try {
   4974                     // TODO - need to handle failures
   4975                     mTransport.finishBackup();
   4976                 } catch (RemoteException e) {
   4977                     // can't happen; the transport is local
   4978                 }
   4979 
   4980                 // Last but not least, release the cpu
   4981                 mWakelock.release();
   4982             }
   4983         }
   4984     }
   4985 
   4986     class PerformInitializeTask implements Runnable {
   4987         HashSet<String> mQueue;
   4988 
   4989         PerformInitializeTask(HashSet<String> transportNames) {
   4990             mQueue = transportNames;
   4991         }
   4992 
   4993         public void run() {
   4994             try {
   4995                 for (String transportName : mQueue) {
   4996                     IBackupTransport transport = getTransport(transportName);
   4997                     if (transport == null) {
   4998                         Slog.e(TAG, "Requested init for " + transportName + " but not found");
   4999                         continue;
   5000                     }
   5001 
   5002                     Slog.i(TAG, "Initializing (wiping) backup transport storage: " + transportName);
   5003                     EventLog.writeEvent(EventLogTags.BACKUP_START, transport.transportDirName());
   5004                     long startRealtime = SystemClock.elapsedRealtime();
   5005                     int status = transport.initializeDevice();
   5006 
   5007                     if (status == BackupConstants.TRANSPORT_OK) {
   5008                         status = transport.finishBackup();
   5009                     }
   5010 
   5011                     // Okay, the wipe really happened.  Clean up our local bookkeeping.
   5012                     if (status == BackupConstants.TRANSPORT_OK) {
   5013                         Slog.i(TAG, "Device init successful");
   5014                         int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
   5015                         EventLog.writeEvent(EventLogTags.BACKUP_INITIALIZE);
   5016                         resetBackupState(new File(mBaseStateDir, transport.transportDirName()));
   5017                         EventLog.writeEvent(EventLogTags.BACKUP_SUCCESS, 0, millis);
   5018                         synchronized (mQueueLock) {
   5019                             recordInitPendingLocked(false, transportName);
   5020                         }
   5021                     } else {
   5022                         // If this didn't work, requeue this one and try again
   5023                         // after a suitable interval
   5024                         Slog.e(TAG, "Transport error in initializeDevice()");
   5025                         EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, "(initialize)");
   5026                         synchronized (mQueueLock) {
   5027                             recordInitPendingLocked(true, transportName);
   5028                         }
   5029                         // do this via another alarm to make sure of the wakelock states
   5030                         long delay = transport.requestBackupTime();
   5031                         if (DEBUG) Slog.w(TAG, "init failed on "
   5032                                 + transportName + " resched in " + delay);
   5033                         mAlarmManager.set(AlarmManager.RTC_WAKEUP,
   5034                                 System.currentTimeMillis() + delay, mRunInitIntent);
   5035                     }
   5036                 }
   5037             } catch (RemoteException e) {
   5038                 // can't happen; the transports are local
   5039             } catch (Exception e) {
   5040                 Slog.e(TAG, "Unexpected error performing init", e);
   5041             } finally {
   5042                 // Done; release the wakelock
   5043                 mWakelock.release();
   5044             }
   5045         }
   5046     }
   5047 
   5048     private void dataChangedImpl(String packageName) {
   5049         HashSet<String> targets = dataChangedTargets(packageName);
   5050         dataChangedImpl(packageName, targets);
   5051     }
   5052 
   5053     private void dataChangedImpl(String packageName, HashSet<String> targets) {
   5054         // Record that we need a backup pass for the caller.  Since multiple callers
   5055         // may share a uid, we need to note all candidates within that uid and schedule
   5056         // a backup pass for each of them.
   5057         EventLog.writeEvent(EventLogTags.BACKUP_DATA_CHANGED, packageName);
   5058 
   5059         if (targets == null) {
   5060             Slog.w(TAG, "dataChanged but no participant pkg='" + packageName + "'"
   5061                    + " uid=" + Binder.getCallingUid());
   5062             return;
   5063         }
   5064 
   5065         synchronized (mQueueLock) {
   5066             // Note that this client has made data changes that need to be backed up
   5067             if (targets.contains(packageName)) {
   5068                 // Add the caller to the set of pending backups.  If there is
   5069                 // one already there, then overwrite it, but no harm done.
   5070                 BackupRequest req = new BackupRequest(packageName);
   5071                 if (mPendingBackups.put(packageName, req) == null) {
   5072                     if (DEBUG) Slog.d(TAG, "Now staging backup of " + packageName);
   5073 
   5074                     // Journal this request in case of crash.  The put()
   5075                     // operation returned null when this package was not already
   5076                     // in the set; we want to avoid touching the disk redundantly.
   5077                     writeToJournalLocked(packageName);
   5078 
   5079                     if (MORE_DEBUG) {
   5080                         int numKeys = mPendingBackups.size();
   5081                         Slog.d(TAG, "Now awaiting backup for " + numKeys + " participants:");
   5082                         for (BackupRequest b : mPendingBackups.values()) {
   5083                             Slog.d(TAG, "    + " + b);
   5084                         }
   5085                     }
   5086                 }
   5087             }
   5088         }
   5089     }
   5090 
   5091     // Note: packageName is currently unused, but may be in the future
   5092     private HashSet<String> dataChangedTargets(String packageName) {
   5093         // If the caller does not hold the BACKUP permission, it can only request a
   5094         // backup of its own data.
   5095         if ((mContext.checkPermission(android.Manifest.permission.BACKUP, Binder.getCallingPid(),
   5096                 Binder.getCallingUid())) == PackageManager.PERMISSION_DENIED) {
   5097             synchronized (mBackupParticipants) {
   5098                 return mBackupParticipants.get(Binder.getCallingUid());
   5099             }
   5100         }
   5101 
   5102         // a caller with full permission can ask to back up any participating app
   5103         // !!! TODO: allow backup of ANY app?
   5104         HashSet<String> targets = new HashSet<String>();
   5105         synchronized (mBackupParticipants) {
   5106             int N = mBackupParticipants.size();
   5107             for (int i = 0; i < N; i++) {
   5108                 HashSet<String> s = mBackupParticipants.valueAt(i);
   5109                 if (s != null) {
   5110                     targets.addAll(s);
   5111                 }
   5112             }
   5113         }
   5114         return targets;
   5115     }
   5116 
   5117     private void writeToJournalLocked(String str) {
   5118         RandomAccessFile out = null;
   5119         try {
   5120             if (mJournal == null) mJournal = File.createTempFile("journal", null, mJournalDir);
   5121             out = new RandomAccessFile(mJournal, "rws");
   5122             out.seek(out.length());
   5123             out.writeUTF(str);
   5124         } catch (IOException e) {
   5125             Slog.e(TAG, "Can't write " + str + " to backup journal", e);
   5126             mJournal = null;
   5127         } finally {
   5128             try { if (out != null) out.close(); } catch (IOException e) {}
   5129         }
   5130     }
   5131 
   5132     // ----- IBackupManager binder interface -----
   5133 
   5134     public void dataChanged(final String packageName) {
   5135         final int callingUserHandle = UserHandle.getCallingUserId();
   5136         if (callingUserHandle != UserHandle.USER_OWNER) {
   5137             // App is running under a non-owner user profile.  For now, we do not back
   5138             // up data from secondary user profiles.
   5139             // TODO: backups for all user profiles.
   5140             if (MORE_DEBUG) {
   5141                 Slog.v(TAG, "dataChanged(" + packageName + ") ignored because it's user "
   5142                         + callingUserHandle);
   5143             }
   5144             return;
   5145         }
   5146 
   5147         final HashSet<String> targets = dataChangedTargets(packageName);
   5148         if (targets == null) {
   5149             Slog.w(TAG, "dataChanged but no participant pkg='" + packageName + "'"
   5150                    + " uid=" + Binder.getCallingUid());
   5151             return;
   5152         }
   5153 
   5154         mBackupHandler.post(new Runnable() {
   5155                 public void run() {
   5156                     dataChangedImpl(packageName, targets);
   5157                 }
   5158             });
   5159     }
   5160 
   5161     // Clear the given package's backup data from the current transport
   5162     public void clearBackupData(String transportName, String packageName) {
   5163         if (DEBUG) Slog.v(TAG, "clearBackupData() of " + packageName + " on " + transportName);
   5164         PackageInfo info;
   5165         try {
   5166             info = mPackageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
   5167         } catch (NameNotFoundException e) {
   5168             Slog.d(TAG, "No such package '" + packageName + "' - not clearing backup data");
   5169             return;
   5170         }
   5171 
   5172         // If the caller does not hold the BACKUP permission, it can only request a
   5173         // wipe of its own backed-up data.
   5174         HashSet<String> apps;
   5175         if ((mContext.checkPermission(android.Manifest.permission.BACKUP, Binder.getCallingPid(),
   5176                 Binder.getCallingUid())) == PackageManager.PERMISSION_DENIED) {
   5177             apps = mBackupParticipants.get(Binder.getCallingUid());
   5178         } else {
   5179             // a caller with full permission can ask to back up any participating app
   5180             // !!! TODO: allow data-clear of ANY app?
   5181             if (DEBUG) Slog.v(TAG, "Privileged caller, allowing clear of other apps");
   5182             apps = new HashSet<String>();
   5183             int N = mBackupParticipants.size();
   5184             for (int i = 0; i < N; i++) {
   5185                 HashSet<String> s = mBackupParticipants.valueAt(i);
   5186                 if (s != null) {
   5187                     apps.addAll(s);
   5188                 }
   5189             }
   5190         }
   5191 
   5192         // Is the given app an available participant?
   5193         if (apps.contains(packageName)) {
   5194             // found it; fire off the clear request
   5195             if (DEBUG) Slog.v(TAG, "Found the app - running clear process");
   5196             mBackupHandler.removeMessages(MSG_RETRY_CLEAR);
   5197             synchronized (mQueueLock) {
   5198                 final IBackupTransport transport = getTransport(transportName);
   5199                 if (transport == null) {
   5200                     // transport is currently unavailable -- make sure to retry
   5201                     Message msg = mBackupHandler.obtainMessage(MSG_RETRY_CLEAR,
   5202                             new ClearRetryParams(transportName, packageName));
   5203                     mBackupHandler.sendMessageDelayed(msg, TRANSPORT_RETRY_INTERVAL);
   5204                     return;
   5205                 }
   5206                 long oldId = Binder.clearCallingIdentity();
   5207                 mWakelock.acquire();
   5208                 Message msg = mBackupHandler.obtainMessage(MSG_RUN_CLEAR,
   5209                         new ClearParams(transport, info));
   5210                 mBackupHandler.sendMessage(msg);
   5211                 Binder.restoreCallingIdentity(oldId);
   5212             }
   5213         }
   5214     }
   5215 
   5216     // Run a backup pass immediately for any applications that have declared
   5217     // that they have pending updates.
   5218     public void backupNow() {
   5219         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "backupNow");
   5220 
   5221         if (DEBUG) Slog.v(TAG, "Scheduling immediate backup pass");
   5222         synchronized (mQueueLock) {
   5223             // Because the alarms we are using can jitter, and we want an *immediate*
   5224             // backup pass to happen, we restart the timer beginning with "next time,"
   5225             // then manually fire the backup trigger intent ourselves.
   5226             startBackupAlarmsLocked(BACKUP_INTERVAL);
   5227             try {
   5228                 mRunBackupIntent.send();
   5229             } catch (PendingIntent.CanceledException e) {
   5230                 // should never happen
   5231                 Slog.e(TAG, "run-backup intent cancelled!");
   5232             }
   5233         }
   5234     }
   5235 
   5236     boolean deviceIsProvisioned() {
   5237         final ContentResolver resolver = mContext.getContentResolver();
   5238         return (Settings.Global.getInt(resolver, Settings.Global.DEVICE_PROVISIONED, 0) != 0);
   5239     }
   5240 
   5241     // Run a *full* backup pass for the given package, writing the resulting data stream
   5242     // to the supplied file descriptor.  This method is synchronous and does not return
   5243     // to the caller until the backup has been completed.
   5244     public void fullBackup(ParcelFileDescriptor fd, boolean includeApks,
   5245             boolean includeObbs, boolean includeShared,
   5246             boolean doAllApps, boolean includeSystem, String[] pkgList) {
   5247         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "fullBackup");
   5248 
   5249         final int callingUserHandle = UserHandle.getCallingUserId();
   5250         if (callingUserHandle != UserHandle.USER_OWNER) {
   5251             throw new IllegalStateException("Backup supported only for the device owner");
   5252         }
   5253 
   5254         // Validate
   5255         if (!doAllApps) {
   5256             if (!includeShared) {
   5257                 // If we're backing up shared data (sdcard or equivalent), then we can run
   5258                 // without any supplied app names.  Otherwise, we'd be doing no work, so
   5259                 // report the error.
   5260                 if (pkgList == null || pkgList.length == 0) {
   5261                     throw new IllegalArgumentException(
   5262                             "Backup requested but neither shared nor any apps named");
   5263                 }
   5264             }
   5265         }
   5266 
   5267         long oldId = Binder.clearCallingIdentity();
   5268         try {
   5269             // Doesn't make sense to do a full backup prior to setup
   5270             if (!deviceIsProvisioned()) {
   5271                 Slog.i(TAG, "Full backup not supported before setup");
   5272                 return;
   5273             }
   5274 
   5275             if (DEBUG) Slog.v(TAG, "Requesting full backup: apks=" + includeApks
   5276                     + " obb=" + includeObbs + " shared=" + includeShared + " all=" + doAllApps
   5277                     + " pkgs=" + pkgList);
   5278             Slog.i(TAG, "Beginning full backup...");
   5279 
   5280             FullBackupParams params = new FullBackupParams(fd, includeApks, includeObbs,
   5281                     includeShared, doAllApps, includeSystem, pkgList);
   5282             final int token = generateToken();
   5283             synchronized (mFullConfirmations) {
   5284                 mFullConfirmations.put(token, params);
   5285             }
   5286 
   5287             // start up the confirmation UI
   5288             if (DEBUG) Slog.d(TAG, "Starting backup confirmation UI, token=" + token);
   5289             if (!startConfirmationUi(token, FullBackup.FULL_BACKUP_INTENT_ACTION)) {
   5290                 Slog.e(TAG, "Unable to launch full backup confirmation");
   5291                 mFullConfirmations.delete(token);
   5292                 return;
   5293             }
   5294 
   5295             // make sure the screen is lit for the user interaction
   5296             mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
   5297 
   5298             // start the confirmation countdown
   5299             startConfirmationTimeout(token, params);
   5300 
   5301             // wait for the backup to be performed
   5302             if (DEBUG) Slog.d(TAG, "Waiting for full backup completion...");
   5303             waitForCompletion(params);
   5304         } finally {
   5305             try {
   5306                 fd.close();
   5307             } catch (IOException e) {
   5308                 // just eat it
   5309             }
   5310             Binder.restoreCallingIdentity(oldId);
   5311             Slog.d(TAG, "Full backup processing complete.");
   5312         }
   5313     }
   5314 
   5315     public void fullRestore(ParcelFileDescriptor fd) {
   5316         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "fullRestore");
   5317 
   5318         final int callingUserHandle = UserHandle.getCallingUserId();
   5319         if (callingUserHandle != UserHandle.USER_OWNER) {
   5320             throw new IllegalStateException("Restore supported only for the device owner");
   5321         }
   5322 
   5323         long oldId = Binder.clearCallingIdentity();
   5324 
   5325         try {
   5326             // Check whether the device has been provisioned -- we don't handle
   5327             // full restores prior to completing the setup process.
   5328             if (!deviceIsProvisioned()) {
   5329                 Slog.i(TAG, "Full restore not permitted before setup");
   5330                 return;
   5331             }
   5332 
   5333             Slog.i(TAG, "Beginning full restore...");
   5334 
   5335             FullRestoreParams params = new FullRestoreParams(fd);
   5336             final int token = generateToken();
   5337             synchronized (mFullConfirmations) {
   5338                 mFullConfirmations.put(token, params);
   5339             }
   5340 
   5341             // start up the confirmation UI
   5342             if (DEBUG) Slog.d(TAG, "Starting restore confirmation UI, token=" + token);
   5343             if (!startConfirmationUi(token, FullBackup.FULL_RESTORE_INTENT_ACTION)) {
   5344                 Slog.e(TAG, "Unable to launch full restore confirmation");
   5345                 mFullConfirmations.delete(token);
   5346                 return;
   5347             }
   5348 
   5349             // make sure the screen is lit for the user interaction
   5350             mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
   5351 
   5352             // start the confirmation countdown
   5353             startConfirmationTimeout(token, params);
   5354 
   5355             // wait for the restore to be performed
   5356             if (DEBUG) Slog.d(TAG, "Waiting for full restore completion...");
   5357             waitForCompletion(params);
   5358         } finally {
   5359             try {
   5360                 fd.close();
   5361             } catch (IOException e) {
   5362                 Slog.w(TAG, "Error trying to close fd after full restore: " + e);
   5363             }
   5364             Binder.restoreCallingIdentity(oldId);
   5365             Slog.i(TAG, "Full restore processing complete.");
   5366         }
   5367     }
   5368 
   5369     boolean startConfirmationUi(int token, String action) {
   5370         try {
   5371             Intent confIntent = new Intent(action);
   5372             confIntent.setClassName("com.android.backupconfirm",
   5373                     "com.android.backupconfirm.BackupRestoreConfirmation");
   5374             confIntent.putExtra(FullBackup.CONF_TOKEN_INTENT_EXTRA, token);
   5375             confIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
   5376             mContext.startActivity(confIntent);
   5377         } catch (ActivityNotFoundException e) {
   5378             return false;
   5379         }
   5380         return true;
   5381     }
   5382 
   5383     void startConfirmationTimeout(int token, FullParams params) {
   5384         if (MORE_DEBUG) Slog.d(TAG, "Posting conf timeout msg after "
   5385                 + TIMEOUT_FULL_CONFIRMATION + " millis");
   5386         Message msg = mBackupHandler.obtainMessage(MSG_FULL_CONFIRMATION_TIMEOUT,
   5387                 token, 0, params);
   5388         mBackupHandler.sendMessageDelayed(msg, TIMEOUT_FULL_CONFIRMATION);
   5389     }
   5390 
   5391     void waitForCompletion(FullParams params) {
   5392         synchronized (params.latch) {
   5393             while (params.latch.get() == false) {
   5394                 try {
   5395                     params.latch.wait();
   5396                 } catch (InterruptedException e) { /* never interrupted */ }
   5397             }
   5398         }
   5399     }
   5400 
   5401     void signalFullBackupRestoreCompletion(FullParams params) {
   5402         synchronized (params.latch) {
   5403             params.latch.set(true);
   5404             params.latch.notifyAll();
   5405         }
   5406     }
   5407 
   5408     // Confirm that the previously-requested full backup/restore operation can proceed.  This
   5409     // is used to require a user-facing disclosure about the operation.
   5410     @Override
   5411     public void acknowledgeFullBackupOrRestore(int token, boolean allow,
   5412             String curPassword, String encPpassword, IFullBackupRestoreObserver observer) {
   5413         if (DEBUG) Slog.d(TAG, "acknowledgeFullBackupOrRestore : token=" + token
   5414                 + " allow=" + allow);
   5415 
   5416         // TODO: possibly require not just this signature-only permission, but even
   5417         // require that the specific designated confirmation-UI app uid is the caller?
   5418         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "acknowledgeFullBackupOrRestore");
   5419 
   5420         long oldId = Binder.clearCallingIdentity();
   5421         try {
   5422 
   5423             FullParams params;
   5424             synchronized (mFullConfirmations) {
   5425                 params = mFullConfirmations.get(token);
   5426                 if (params != null) {
   5427                     mBackupHandler.removeMessages(MSG_FULL_CONFIRMATION_TIMEOUT, params);
   5428                     mFullConfirmations.delete(token);
   5429 
   5430                     if (allow) {
   5431                         final int verb = params instanceof FullBackupParams
   5432                                 ? MSG_RUN_FULL_BACKUP
   5433                                 : MSG_RUN_FULL_RESTORE;
   5434 
   5435                         params.observer = observer;
   5436                         params.curPassword = curPassword;
   5437 
   5438                         boolean isEncrypted;
   5439                         try {
   5440                             isEncrypted = (mMountService.getEncryptionState() != MountService.ENCRYPTION_STATE_NONE);
   5441                             if (isEncrypted) Slog.w(TAG, "Device is encrypted; forcing enc password");
   5442                         } catch (RemoteException e) {
   5443                             // couldn't contact the mount service; fail "safe" and assume encryption
   5444                             Slog.e(TAG, "Unable to contact mount service!");
   5445                             isEncrypted = true;
   5446                         }
   5447                         params.encryptPassword = (isEncrypted) ? curPassword : encPpassword;
   5448 
   5449                         if (DEBUG) Slog.d(TAG, "Sending conf message with verb " + verb);
   5450                         mWakelock.acquire();
   5451                         Message msg = mBackupHandler.obtainMessage(verb, params);
   5452                         mBackupHandler.sendMessage(msg);
   5453                     } else {
   5454                         Slog.w(TAG, "User rejected full backup/restore operation");
   5455                         // indicate completion without having actually transferred any data
   5456                         signalFullBackupRestoreCompletion(params);
   5457                     }
   5458                 } else {
   5459                     Slog.w(TAG, "Attempted to ack full backup/restore with invalid token");
   5460                 }
   5461             }
   5462         } finally {
   5463             Binder.restoreCallingIdentity(oldId);
   5464         }
   5465     }
   5466 
   5467     // Enable/disable the backup service
   5468     @Override
   5469     public void setBackupEnabled(boolean enable) {
   5470         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   5471                 "setBackupEnabled");
   5472 
   5473         Slog.i(TAG, "Backup enabled => " + enable);
   5474 
   5475         long oldId = Binder.clearCallingIdentity();
   5476         try {
   5477             boolean wasEnabled = mEnabled;
   5478             synchronized (this) {
   5479                 Settings.Secure.putInt(mContext.getContentResolver(),
   5480                         Settings.Secure.BACKUP_ENABLED, enable ? 1 : 0);
   5481                 mEnabled = enable;
   5482             }
   5483 
   5484             synchronized (mQueueLock) {
   5485                 if (enable && !wasEnabled && mProvisioned) {
   5486                     // if we've just been enabled, start scheduling backup passes
   5487                     startBackupAlarmsLocked(BACKUP_INTERVAL);
   5488                 } else if (!enable) {
   5489                     // No longer enabled, so stop running backups
   5490                     if (DEBUG) Slog.i(TAG, "Opting out of backup");
   5491 
   5492                     mAlarmManager.cancel(mRunBackupIntent);
   5493 
   5494                     // This also constitutes an opt-out, so we wipe any data for
   5495                     // this device from the backend.  We start that process with
   5496                     // an alarm in order to guarantee wakelock states.
   5497                     if (wasEnabled && mProvisioned) {
   5498                         // NOTE: we currently flush every registered transport, not just
   5499                         // the currently-active one.
   5500                         HashSet<String> allTransports;
   5501                         synchronized (mTransports) {
   5502                             allTransports = new HashSet<String>(mTransports.keySet());
   5503                         }
   5504                         // build the set of transports for which we are posting an init
   5505                         for (String transport : allTransports) {
   5506                             recordInitPendingLocked(true, transport);
   5507                         }
   5508                         mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
   5509                                 mRunInitIntent);
   5510                     }
   5511                 }
   5512             }
   5513         } finally {
   5514             Binder.restoreCallingIdentity(oldId);
   5515         }
   5516     }
   5517 
   5518     // Enable/disable automatic restore of app data at install time
   5519     public void setAutoRestore(boolean doAutoRestore) {
   5520         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   5521                 "setAutoRestore");
   5522 
   5523         Slog.i(TAG, "Auto restore => " + doAutoRestore);
   5524 
   5525         synchronized (this) {
   5526             Settings.Secure.putInt(mContext.getContentResolver(),
   5527                     Settings.Secure.BACKUP_AUTO_RESTORE, doAutoRestore ? 1 : 0);
   5528             mAutoRestore = doAutoRestore;
   5529         }
   5530     }
   5531 
   5532     // Mark the backup service as having been provisioned
   5533     public void setBackupProvisioned(boolean available) {
   5534         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   5535                 "setBackupProvisioned");
   5536         /*
   5537          * This is now a no-op; provisioning is simply the device's own setup state.
   5538          */
   5539     }
   5540 
   5541     private void startBackupAlarmsLocked(long delayBeforeFirstBackup) {
   5542         // We used to use setInexactRepeating(), but that may be linked to
   5543         // backups running at :00 more often than not, creating load spikes.
   5544         // Schedule at an exact time for now, and also add a bit of "fuzz".
   5545 
   5546         Random random = new Random();
   5547         long when = System.currentTimeMillis() + delayBeforeFirstBackup +
   5548                 random.nextInt(FUZZ_MILLIS);
   5549         mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, when,
   5550                 BACKUP_INTERVAL + random.nextInt(FUZZ_MILLIS), mRunBackupIntent);
   5551         mNextBackupPass = when;
   5552     }
   5553 
   5554     // Report whether the backup mechanism is currently enabled
   5555     public boolean isBackupEnabled() {
   5556         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "isBackupEnabled");
   5557         return mEnabled;    // no need to synchronize just to read it
   5558     }
   5559 
   5560     // Report the name of the currently active transport
   5561     public String getCurrentTransport() {
   5562         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   5563                 "getCurrentTransport");
   5564         if (MORE_DEBUG) Slog.v(TAG, "... getCurrentTransport() returning " + mCurrentTransport);
   5565         return mCurrentTransport;
   5566     }
   5567 
   5568     // Report all known, available backup transports
   5569     public String[] listAllTransports() {
   5570         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "listAllTransports");
   5571 
   5572         String[] list = null;
   5573         ArrayList<String> known = new ArrayList<String>();
   5574         for (Map.Entry<String, IBackupTransport> entry : mTransports.entrySet()) {
   5575             if (entry.getValue() != null) {
   5576                 known.add(entry.getKey());
   5577             }
   5578         }
   5579 
   5580         if (known.size() > 0) {
   5581             list = new String[known.size()];
   5582             known.toArray(list);
   5583         }
   5584         return list;
   5585     }
   5586 
   5587     // Select which transport to use for the next backup operation.  If the given
   5588     // name is not one of the available transports, no action is taken and the method
   5589     // returns null.
   5590     public String selectBackupTransport(String transport) {
   5591         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "selectBackupTransport");
   5592 
   5593         synchronized (mTransports) {
   5594             String prevTransport = null;
   5595             if (mTransports.get(transport) != null) {
   5596                 prevTransport = mCurrentTransport;
   5597                 mCurrentTransport = transport;
   5598                 Settings.Secure.putString(mContext.getContentResolver(),
   5599                         Settings.Secure.BACKUP_TRANSPORT, transport);
   5600                 Slog.v(TAG, "selectBackupTransport() set " + mCurrentTransport
   5601                         + " returning " + prevTransport);
   5602             } else {
   5603                 Slog.w(TAG, "Attempt to select unavailable transport " + transport);
   5604             }
   5605             return prevTransport;
   5606         }
   5607     }
   5608 
   5609     // Supply the configuration Intent for the given transport.  If the name is not one
   5610     // of the available transports, or if the transport does not supply any configuration
   5611     // UI, the method returns null.
   5612     public Intent getConfigurationIntent(String transportName) {
   5613         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   5614                 "getConfigurationIntent");
   5615 
   5616         synchronized (mTransports) {
   5617             final IBackupTransport transport = mTransports.get(transportName);
   5618             if (transport != null) {
   5619                 try {
   5620                     final Intent intent = transport.configurationIntent();
   5621                     if (MORE_DEBUG) Slog.d(TAG, "getConfigurationIntent() returning config intent "
   5622                             + intent);
   5623                     return intent;
   5624                 } catch (RemoteException e) {
   5625                     /* fall through to return null */
   5626                 }
   5627             }
   5628         }
   5629 
   5630         return null;
   5631     }
   5632 
   5633     // Supply the configuration summary string for the given transport.  If the name is
   5634     // not one of the available transports, or if the transport does not supply any
   5635     // summary / destination string, the method can return null.
   5636     //
   5637     // This string is used VERBATIM as the summary text of the relevant Settings item!
   5638     public String getDestinationString(String transportName) {
   5639         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   5640                 "getDestinationString");
   5641 
   5642         synchronized (mTransports) {
   5643             final IBackupTransport transport = mTransports.get(transportName);
   5644             if (transport != null) {
   5645                 try {
   5646                     final String text = transport.currentDestinationString();
   5647                     if (MORE_DEBUG) Slog.d(TAG, "getDestinationString() returning " + text);
   5648                     return text;
   5649                 } catch (RemoteException e) {
   5650                     /* fall through to return null */
   5651                 }
   5652             }
   5653         }
   5654 
   5655         return null;
   5656     }
   5657 
   5658     // Callback: a requested backup agent has been instantiated.  This should only
   5659     // be called from the Activity Manager.
   5660     public void agentConnected(String packageName, IBinder agentBinder) {
   5661         synchronized(mAgentConnectLock) {
   5662             if (Binder.getCallingUid() == Process.SYSTEM_UID) {
   5663                 Slog.d(TAG, "agentConnected pkg=" + packageName + " agent=" + agentBinder);
   5664                 IBackupAgent agent = IBackupAgent.Stub.asInterface(agentBinder);
   5665                 mConnectedAgent = agent;
   5666                 mConnecting = false;
   5667             } else {
   5668                 Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
   5669                         + " claiming agent connected");
   5670             }
   5671             mAgentConnectLock.notifyAll();
   5672         }
   5673     }
   5674 
   5675     // Callback: a backup agent has failed to come up, or has unexpectedly quit.
   5676     // If the agent failed to come up in the first place, the agentBinder argument
   5677     // will be null.  This should only be called from the Activity Manager.
   5678     public void agentDisconnected(String packageName) {
   5679         // TODO: handle backup being interrupted
   5680         synchronized(mAgentConnectLock) {
   5681             if (Binder.getCallingUid() == Process.SYSTEM_UID) {
   5682                 mConnectedAgent = null;
   5683                 mConnecting = false;
   5684             } else {
   5685                 Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
   5686                         + " claiming agent disconnected");
   5687             }
   5688             mAgentConnectLock.notifyAll();
   5689         }
   5690     }
   5691 
   5692     // An application being installed will need a restore pass, then the Package Manager
   5693     // will need to be told when the restore is finished.
   5694     public void restoreAtInstall(String packageName, int token) {
   5695         if (Binder.getCallingUid() != Process.SYSTEM_UID) {
   5696             Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
   5697                     + " attemping install-time restore");
   5698             return;
   5699         }
   5700 
   5701         long restoreSet = getAvailableRestoreToken(packageName);
   5702         if (DEBUG) Slog.v(TAG, "restoreAtInstall pkg=" + packageName
   5703                 + " token=" + Integer.toHexString(token)
   5704                 + " restoreSet=" + Long.toHexString(restoreSet));
   5705 
   5706         if (mAutoRestore && mProvisioned && restoreSet != 0) {
   5707             // Do we have a transport to fetch data for us?
   5708             IBackupTransport transport = getTransport(mCurrentTransport);
   5709             if (transport == null) {
   5710                 if (DEBUG) Slog.w(TAG, "No transport for install-time restore");
   5711                 return;
   5712             }
   5713 
   5714             try {
   5715                 // okay, we're going to attempt a restore of this package from this restore set.
   5716                 // The eventual message back into the Package Manager to run the post-install
   5717                 // steps for 'token' will be issued from the restore handling code.
   5718 
   5719                 // This can throw and so *must* happen before the wakelock is acquired
   5720                 String dirName = transport.transportDirName();
   5721 
   5722                 // We can use a synthetic PackageInfo here because:
   5723                 //   1. We know it's valid, since the Package Manager supplied the name
   5724                 //   2. Only the packageName field will be used by the restore code
   5725                 PackageInfo pkg = new PackageInfo();
   5726                 pkg.packageName = packageName;
   5727 
   5728                 mWakelock.acquire();
   5729                 Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
   5730                 msg.obj = new RestoreParams(transport, dirName, null,
   5731                         restoreSet, pkg, token, true);
   5732                 mBackupHandler.sendMessage(msg);
   5733             } catch (RemoteException e) {
   5734                 // Binding to the transport broke; back off and proceed with the installation.
   5735                 Slog.e(TAG, "Unable to contact transport for install-time restore");
   5736             }
   5737         } else {
   5738             // Auto-restore disabled or no way to attempt a restore; just tell the Package
   5739             // Manager to proceed with the post-install handling for this package.
   5740             if (DEBUG) Slog.v(TAG, "No restore set -- skipping restore");
   5741             try {
   5742                 mPackageManagerBinder.finishPackageInstall(token);
   5743             } catch (RemoteException e) { /* can't happen */ }
   5744         }
   5745     }
   5746 
   5747     // Hand off a restore session
   5748     public IRestoreSession beginRestoreSession(String packageName, String transport) {
   5749         if (DEBUG) Slog.v(TAG, "beginRestoreSession: pkg=" + packageName
   5750                 + " transport=" + transport);
   5751 
   5752         boolean needPermission = true;
   5753         if (transport == null) {
   5754             transport = mCurrentTransport;
   5755 
   5756             if (packageName != null) {
   5757                 PackageInfo app = null;
   5758                 try {
   5759                     app = mPackageManager.getPackageInfo(packageName, 0);
   5760                 } catch (NameNotFoundException nnf) {
   5761                     Slog.w(TAG, "Asked to restore nonexistent pkg " + packageName);
   5762                     throw new IllegalArgumentException("Package " + packageName + " not found");
   5763                 }
   5764 
   5765                 if (app.applicationInfo.uid == Binder.getCallingUid()) {
   5766                     // So: using the current active transport, and the caller has asked
   5767                     // that its own package will be restored.  In this narrow use case
   5768                     // we do not require the caller to hold the permission.
   5769                     needPermission = false;
   5770                 }
   5771             }
   5772         }
   5773 
   5774         if (needPermission) {
   5775             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   5776                     "beginRestoreSession");
   5777         } else {
   5778             if (DEBUG) Slog.d(TAG, "restoring self on current transport; no permission needed");
   5779         }
   5780 
   5781         synchronized(this) {
   5782             if (mActiveRestoreSession != null) {
   5783                 Slog.d(TAG, "Restore session requested but one already active");
   5784                 return null;
   5785             }
   5786             mActiveRestoreSession = new ActiveRestoreSession(packageName, transport);
   5787             mBackupHandler.sendEmptyMessageDelayed(MSG_RESTORE_TIMEOUT, TIMEOUT_RESTORE_INTERVAL);
   5788         }
   5789         return mActiveRestoreSession;
   5790     }
   5791 
   5792     void clearRestoreSession(ActiveRestoreSession currentSession) {
   5793         synchronized(this) {
   5794             if (currentSession != mActiveRestoreSession) {
   5795                 Slog.e(TAG, "ending non-current restore session");
   5796             } else {
   5797                 if (DEBUG) Slog.v(TAG, "Clearing restore session and halting timeout");
   5798                 mActiveRestoreSession = null;
   5799                 mBackupHandler.removeMessages(MSG_RESTORE_TIMEOUT);
   5800             }
   5801         }
   5802     }
   5803 
   5804     // Note that a currently-active backup agent has notified us that it has
   5805     // completed the given outstanding asynchronous backup/restore operation.
   5806     @Override
   5807     public void opComplete(int token) {
   5808         if (MORE_DEBUG) Slog.v(TAG, "opComplete: " + Integer.toHexString(token));
   5809         Operation op = null;
   5810         synchronized (mCurrentOpLock) {
   5811             op = mCurrentOperations.get(token);
   5812             if (op != null) {
   5813                 op.state = OP_ACKNOWLEDGED;
   5814             }
   5815             mCurrentOpLock.notifyAll();
   5816         }
   5817 
   5818         // The completion callback, if any, is invoked on the handler
   5819         if (op != null && op.callback != null) {
   5820             Message msg = mBackupHandler.obtainMessage(MSG_OP_COMPLETE, op.callback);
   5821             mBackupHandler.sendMessage(msg);
   5822         }
   5823     }
   5824 
   5825     // ----- Restore session -----
   5826 
   5827     class ActiveRestoreSession extends IRestoreSession.Stub {
   5828         private static final String TAG = "RestoreSession";
   5829 
   5830         private String mPackageName;
   5831         private IBackupTransport mRestoreTransport = null;
   5832         RestoreSet[] mRestoreSets = null;
   5833         boolean mEnded = false;
   5834 
   5835         ActiveRestoreSession(String packageName, String transport) {
   5836             mPackageName = packageName;
   5837             mRestoreTransport = getTransport(transport);
   5838         }
   5839 
   5840         // --- Binder interface ---
   5841         public synchronized int getAvailableRestoreSets(IRestoreObserver observer) {
   5842             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   5843                     "getAvailableRestoreSets");
   5844             if (observer == null) {
   5845                 throw new IllegalArgumentException("Observer must not be null");
   5846             }
   5847 
   5848             if (mEnded) {
   5849                 throw new IllegalStateException("Restore session already ended");
   5850             }
   5851 
   5852             long oldId = Binder.clearCallingIdentity();
   5853             try {
   5854                 if (mRestoreTransport == null) {
   5855                     Slog.w(TAG, "Null transport getting restore sets");
   5856                     return -1;
   5857                 }
   5858                 // spin off the transport request to our service thread
   5859                 mWakelock.acquire();
   5860                 Message msg = mBackupHandler.obtainMessage(MSG_RUN_GET_RESTORE_SETS,
   5861                         new RestoreGetSetsParams(mRestoreTransport, this, observer));
   5862                 mBackupHandler.sendMessage(msg);
   5863                 return 0;
   5864             } catch (Exception e) {
   5865                 Slog.e(TAG, "Error in getAvailableRestoreSets", e);
   5866                 return -1;
   5867             } finally {
   5868                 Binder.restoreCallingIdentity(oldId);
   5869             }
   5870         }
   5871 
   5872         public synchronized int restoreAll(long token, IRestoreObserver observer) {
   5873             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   5874                     "performRestore");
   5875 
   5876             if (DEBUG) Slog.d(TAG, "restoreAll token=" + Long.toHexString(token)
   5877                     + " observer=" + observer);
   5878 
   5879             if (mEnded) {
   5880                 throw new IllegalStateException("Restore session already ended");
   5881             }
   5882 
   5883             if (mRestoreTransport == null || mRestoreSets == null) {
   5884                 Slog.e(TAG, "Ignoring restoreAll() with no restore set");
   5885                 return -1;
   5886             }
   5887 
   5888             if (mPackageName != null) {
   5889                 Slog.e(TAG, "Ignoring restoreAll() on single-package session");
   5890                 return -1;
   5891             }
   5892 
   5893             String dirName;
   5894             try {
   5895                 dirName = mRestoreTransport.transportDirName();
   5896             } catch (RemoteException e) {
   5897                 // Transport went AWOL; fail.
   5898                 Slog.e(TAG, "Unable to contact transport for restore");
   5899                 return -1;
   5900             }
   5901 
   5902             synchronized (mQueueLock) {
   5903                 for (int i = 0; i < mRestoreSets.length; i++) {
   5904                     if (token == mRestoreSets[i].token) {
   5905                         long oldId = Binder.clearCallingIdentity();
   5906                         mWakelock.acquire();
   5907                         Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
   5908                         msg.obj = new RestoreParams(mRestoreTransport, dirName,
   5909                                 observer, token, true);
   5910                         mBackupHandler.sendMessage(msg);
   5911                         Binder.restoreCallingIdentity(oldId);
   5912                         return 0;
   5913                     }
   5914                 }
   5915             }
   5916 
   5917             Slog.w(TAG, "Restore token " + Long.toHexString(token) + " not found");
   5918             return -1;
   5919         }
   5920 
   5921         public synchronized int restoreSome(long token, IRestoreObserver observer,
   5922                 String[] packages) {
   5923             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   5924                     "performRestore");
   5925 
   5926             if (DEBUG) {
   5927                 StringBuilder b = new StringBuilder(128);
   5928                 b.append("restoreSome token=");
   5929                 b.append(Long.toHexString(token));
   5930                 b.append(" observer=");
   5931                 b.append(observer.toString());
   5932                 b.append(" packages=");
   5933                 if (packages == null) {
   5934                     b.append("null");
   5935                 } else {
   5936                     b.append('{');
   5937                     boolean first = true;
   5938                     for (String s : packages) {
   5939                         if (!first) {
   5940                             b.append(", ");
   5941                         } else first = false;
   5942                         b.append(s);
   5943                     }
   5944                     b.append('}');
   5945                 }
   5946                 Slog.d(TAG, b.toString());
   5947             }
   5948 
   5949             if (mEnded) {
   5950                 throw new IllegalStateException("Restore session already ended");
   5951             }
   5952 
   5953             if (mRestoreTransport == null || mRestoreSets == null) {
   5954                 Slog.e(TAG, "Ignoring restoreAll() with no restore set");
   5955                 return -1;
   5956             }
   5957 
   5958             if (mPackageName != null) {
   5959                 Slog.e(TAG, "Ignoring restoreAll() on single-package session");
   5960                 return -1;
   5961             }
   5962 
   5963             String dirName;
   5964             try {
   5965                 dirName = mRestoreTransport.transportDirName();
   5966             } catch (RemoteException e) {
   5967                 // Transport went AWOL; fail.
   5968                 Slog.e(TAG, "Unable to contact transport for restore");
   5969                 return -1;
   5970             }
   5971 
   5972             synchronized (mQueueLock) {
   5973                 for (int i = 0; i < mRestoreSets.length; i++) {
   5974                     if (token == mRestoreSets[i].token) {
   5975                         long oldId = Binder.clearCallingIdentity();
   5976                         mWakelock.acquire();
   5977                         Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
   5978                         msg.obj = new RestoreParams(mRestoreTransport, dirName, observer, token,
   5979                                 packages, true);
   5980                         mBackupHandler.sendMessage(msg);
   5981                         Binder.restoreCallingIdentity(oldId);
   5982                         return 0;
   5983                     }
   5984                 }
   5985             }
   5986 
   5987             Slog.w(TAG, "Restore token " + Long.toHexString(token) + " not found");
   5988             return -1;
   5989         }
   5990 
   5991         public synchronized int restorePackage(String packageName, IRestoreObserver observer) {
   5992             if (DEBUG) Slog.v(TAG, "restorePackage pkg=" + packageName + " obs=" + observer);
   5993 
   5994             if (mEnded) {
   5995                 throw new IllegalStateException("Restore session already ended");
   5996             }
   5997 
   5998             if (mPackageName != null) {
   5999                 if (! mPackageName.equals(packageName)) {
   6000                     Slog.e(TAG, "Ignoring attempt to restore pkg=" + packageName
   6001                             + " on session for package " + mPackageName);
   6002                     return -1;
   6003                 }
   6004             }
   6005 
   6006             PackageInfo app = null;
   6007             try {
   6008                 app = mPackageManager.getPackageInfo(packageName, 0);
   6009             } catch (NameNotFoundException nnf) {
   6010                 Slog.w(TAG, "Asked to restore nonexistent pkg " + packageName);
   6011                 return -1;
   6012             }
   6013 
   6014             // If the caller is not privileged and is not coming from the target
   6015             // app's uid, throw a permission exception back to the caller.
   6016             int perm = mContext.checkPermission(android.Manifest.permission.BACKUP,
   6017                     Binder.getCallingPid(), Binder.getCallingUid());
   6018             if ((perm == PackageManager.PERMISSION_DENIED) &&
   6019                     (app.applicationInfo.uid != Binder.getCallingUid())) {
   6020                 Slog.w(TAG, "restorePackage: bad packageName=" + packageName
   6021                         + " or calling uid=" + Binder.getCallingUid());
   6022                 throw new SecurityException("No permission to restore other packages");
   6023             }
   6024 
   6025             // If the package has no backup agent, we obviously cannot proceed
   6026             if (app.applicationInfo.backupAgentName == null) {
   6027                 Slog.w(TAG, "Asked to restore package " + packageName + " with no agent");
   6028                 return -1;
   6029             }
   6030 
   6031             // So far so good; we're allowed to try to restore this package.  Now
   6032             // check whether there is data for it in the current dataset, falling back
   6033             // to the ancestral dataset if not.
   6034             long token = getAvailableRestoreToken(packageName);
   6035 
   6036             // If we didn't come up with a place to look -- no ancestral dataset and
   6037             // the app has never been backed up from this device -- there's nothing
   6038             // to do but return failure.
   6039             if (token == 0) {
   6040                 if (DEBUG) Slog.w(TAG, "No data available for this package; not restoring");
   6041                 return -1;
   6042             }
   6043 
   6044             String dirName;
   6045             try {
   6046                 dirName = mRestoreTransport.transportDirName();
   6047             } catch (RemoteException e) {
   6048                 // Transport went AWOL; fail.
   6049                 Slog.e(TAG, "Unable to contact transport for restore");
   6050                 return -1;
   6051             }
   6052 
   6053             // Ready to go:  enqueue the restore request and claim success
   6054             long oldId = Binder.clearCallingIdentity();
   6055             mWakelock.acquire();
   6056             Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
   6057             msg.obj = new RestoreParams(mRestoreTransport, dirName,
   6058                     observer, token, app, 0, false);
   6059             mBackupHandler.sendMessage(msg);
   6060             Binder.restoreCallingIdentity(oldId);
   6061             return 0;
   6062         }
   6063 
   6064         // Posted to the handler to tear down a restore session in a cleanly synchronized way
   6065         class EndRestoreRunnable implements Runnable {
   6066             BackupManagerService mBackupManager;
   6067             ActiveRestoreSession mSession;
   6068 
   6069             EndRestoreRunnable(BackupManagerService manager, ActiveRestoreSession session) {
   6070                 mBackupManager = manager;
   6071                 mSession = session;
   6072             }
   6073 
   6074             public void run() {
   6075                 // clean up the session's bookkeeping
   6076                 synchronized (mSession) {
   6077                     try {
   6078                         if (mSession.mRestoreTransport != null) {
   6079                             mSession.mRestoreTransport.finishRestore();
   6080                         }
   6081                     } catch (Exception e) {
   6082                         Slog.e(TAG, "Error in finishRestore", e);
   6083                     } finally {
   6084                         mSession.mRestoreTransport = null;
   6085                         mSession.mEnded = true;
   6086                     }
   6087                 }
   6088 
   6089                 // clean up the BackupManagerService side of the bookkeeping
   6090                 // and cancel any pending timeout message
   6091                 mBackupManager.clearRestoreSession(mSession);
   6092             }
   6093         }
   6094 
   6095         public synchronized void endRestoreSession() {
   6096             if (DEBUG) Slog.d(TAG, "endRestoreSession");
   6097 
   6098             if (mEnded) {
   6099                 throw new IllegalStateException("Restore session already ended");
   6100             }
   6101 
   6102             mBackupHandler.post(new EndRestoreRunnable(BackupManagerService.this, this));
   6103         }
   6104     }
   6105 
   6106     @Override
   6107     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   6108         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
   6109 
   6110         long identityToken = Binder.clearCallingIdentity();
   6111         try {
   6112             dumpInternal(pw);
   6113         } finally {
   6114             Binder.restoreCallingIdentity(identityToken);
   6115         }
   6116     }
   6117 
   6118     private void dumpInternal(PrintWriter pw) {
   6119         synchronized (mQueueLock) {
   6120             pw.println("Backup Manager is " + (mEnabled ? "enabled" : "disabled")
   6121                     + " / " + (!mProvisioned ? "not " : "") + "provisioned / "
   6122                     + (this.mPendingInits.size() == 0 ? "not " : "") + "pending init");
   6123             pw.println("Auto-restore is " + (mAutoRestore ? "enabled" : "disabled"));
   6124             if (mBackupRunning) pw.println("Backup currently running");
   6125             pw.println("Last backup pass started: " + mLastBackupPass
   6126                     + " (now = " + System.currentTimeMillis() + ')');
   6127             pw.println("  next scheduled: " + mNextBackupPass);
   6128 
   6129             pw.println("Available transports:");
   6130             for (String t : listAllTransports()) {
   6131                 pw.println((t.equals(mCurrentTransport) ? "  * " : "    ") + t);
   6132                 try {
   6133                     IBackupTransport transport = getTransport(t);
   6134                     File dir = new File(mBaseStateDir, transport.transportDirName());
   6135                     pw.println("       destination: " + transport.currentDestinationString());
   6136                     pw.println("       intent: " + transport.configurationIntent());
   6137                     for (File f : dir.listFiles()) {
   6138                         pw.println("       " + f.getName() + " - " + f.length() + " state bytes");
   6139                     }
   6140                 } catch (Exception e) {
   6141                     Slog.e(TAG, "Error in transport", e);
   6142                     pw.println("        Error: " + e);
   6143                 }
   6144             }
   6145 
   6146             pw.println("Pending init: " + mPendingInits.size());
   6147             for (String s : mPendingInits) {
   6148                 pw.println("    " + s);
   6149             }
   6150 
   6151             if (DEBUG_BACKUP_TRACE) {
   6152                 synchronized (mBackupTrace) {
   6153                     if (!mBackupTrace.isEmpty()) {
   6154                         pw.println("Most recent backup trace:");
   6155                         for (String s : mBackupTrace) {
   6156                             pw.println("   " + s);
   6157                         }
   6158                     }
   6159                 }
   6160             }
   6161 
   6162             int N = mBackupParticipants.size();
   6163             pw.println("Participants:");
   6164             for (int i=0; i<N; i++) {
   6165                 int uid = mBackupParticipants.keyAt(i);
   6166                 pw.print("  uid: ");
   6167                 pw.println(uid);
   6168                 HashSet<String> participants = mBackupParticipants.valueAt(i);
   6169                 for (String app: participants) {
   6170                     pw.println("    " + app);
   6171                 }
   6172             }
   6173 
   6174             pw.println("Ancestral packages: "
   6175                     + (mAncestralPackages == null ? "none" : mAncestralPackages.size()));
   6176             if (mAncestralPackages != null) {
   6177                 for (String pkg : mAncestralPackages) {
   6178                     pw.println("    " + pkg);
   6179                 }
   6180             }
   6181 
   6182             pw.println("Ever backed up: " + mEverStoredApps.size());
   6183             for (String pkg : mEverStoredApps) {
   6184                 pw.println("    " + pkg);
   6185             }
   6186 
   6187             pw.println("Pending backup: " + mPendingBackups.size());
   6188             for (BackupRequest req : mPendingBackups.values()) {
   6189                 pw.println("    " + req);
   6190             }
   6191         }
   6192     }
   6193 }
   6194