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