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