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