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