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