Home | History | Annotate | Download | only in backup
      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.backup;
     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.BackupDataInput;
     28 import android.app.backup.BackupDataOutput;
     29 import android.app.backup.BackupTransport;
     30 import android.app.backup.FullBackup;
     31 import android.app.backup.RestoreDescription;
     32 import android.app.backup.RestoreSet;
     33 import android.app.backup.IBackupManager;
     34 import android.app.backup.IFullBackupRestoreObserver;
     35 import android.app.backup.IRestoreObserver;
     36 import android.app.backup.IRestoreSession;
     37 import android.content.ActivityNotFoundException;
     38 import android.content.BroadcastReceiver;
     39 import android.content.ComponentName;
     40 import android.content.ContentResolver;
     41 import android.content.Context;
     42 import android.content.Intent;
     43 import android.content.IntentFilter;
     44 import android.content.ServiceConnection;
     45 import android.content.pm.ApplicationInfo;
     46 import android.content.pm.IPackageDataObserver;
     47 import android.content.pm.IPackageDeleteObserver;
     48 import android.content.pm.IPackageInstallObserver;
     49 import android.content.pm.IPackageManager;
     50 import android.content.pm.PackageInfo;
     51 import android.content.pm.PackageManager;
     52 import android.content.pm.ResolveInfo;
     53 import android.content.pm.ServiceInfo;
     54 import android.content.pm.Signature;
     55 import android.content.pm.PackageManager.NameNotFoundException;
     56 import android.database.ContentObserver;
     57 import android.net.Uri;
     58 import android.os.Binder;
     59 import android.os.Build;
     60 import android.os.Bundle;
     61 import android.os.Environment;
     62 import android.os.Handler;
     63 import android.os.HandlerThread;
     64 import android.os.IBinder;
     65 import android.os.Looper;
     66 import android.os.Message;
     67 import android.os.ParcelFileDescriptor;
     68 import android.os.PowerManager;
     69 import android.os.Process;
     70 import android.os.RemoteException;
     71 import android.os.SELinux;
     72 import android.os.ServiceManager;
     73 import android.os.SystemClock;
     74 import android.os.UserHandle;
     75 import android.os.WorkSource;
     76 import android.os.Environment.UserEnvironment;
     77 import android.os.storage.IMountService;
     78 import android.os.storage.StorageManager;
     79 import android.provider.Settings;
     80 import android.system.ErrnoException;
     81 import android.system.Os;
     82 import android.util.ArrayMap;
     83 import android.util.AtomicFile;
     84 import android.util.EventLog;
     85 import android.util.Log;
     86 import android.util.Slog;
     87 import android.util.SparseArray;
     88 import android.util.StringBuilderPrinter;
     89 
     90 import com.android.internal.backup.IBackupTransport;
     91 import com.android.internal.backup.IObbBackupService;
     92 import com.android.server.AppWidgetBackupBridge;
     93 import com.android.server.EventLogTags;
     94 import com.android.server.SystemService;
     95 import com.android.server.backup.PackageManagerBackupAgent.Metadata;
     96 
     97 import java.io.BufferedInputStream;
     98 import java.io.BufferedOutputStream;
     99 import java.io.ByteArrayInputStream;
    100 import java.io.ByteArrayOutputStream;
    101 import java.io.DataInputStream;
    102 import java.io.DataOutputStream;
    103 import java.io.EOFException;
    104 import java.io.File;
    105 import java.io.FileDescriptor;
    106 import java.io.FileInputStream;
    107 import java.io.FileNotFoundException;
    108 import java.io.FileOutputStream;
    109 import java.io.IOException;
    110 import java.io.InputStream;
    111 import java.io.OutputStream;
    112 import java.io.PrintWriter;
    113 import java.io.RandomAccessFile;
    114 import java.security.InvalidAlgorithmParameterException;
    115 import java.security.InvalidKeyException;
    116 import java.security.Key;
    117 import java.security.MessageDigest;
    118 import java.security.NoSuchAlgorithmException;
    119 import java.security.SecureRandom;
    120 import java.security.spec.InvalidKeySpecException;
    121 import java.security.spec.KeySpec;
    122 import java.text.SimpleDateFormat;
    123 import java.util.ArrayList;
    124 import java.util.Arrays;
    125 import java.util.Collections;
    126 import java.util.Date;
    127 import java.util.HashMap;
    128 import java.util.HashSet;
    129 import java.util.Iterator;
    130 import java.util.List;
    131 import java.util.Map;
    132 import java.util.Map.Entry;
    133 import java.util.Random;
    134 import java.util.Set;
    135 import java.util.TreeMap;
    136 import java.util.concurrent.atomic.AtomicBoolean;
    137 import java.util.concurrent.atomic.AtomicInteger;
    138 import java.util.zip.Deflater;
    139 import java.util.zip.DeflaterOutputStream;
    140 import java.util.zip.InflaterInputStream;
    141 
    142 import javax.crypto.BadPaddingException;
    143 import javax.crypto.Cipher;
    144 import javax.crypto.CipherInputStream;
    145 import javax.crypto.CipherOutputStream;
    146 import javax.crypto.IllegalBlockSizeException;
    147 import javax.crypto.NoSuchPaddingException;
    148 import javax.crypto.SecretKey;
    149 import javax.crypto.SecretKeyFactory;
    150 import javax.crypto.spec.IvParameterSpec;
    151 import javax.crypto.spec.PBEKeySpec;
    152 import javax.crypto.spec.SecretKeySpec;
    153 
    154 import libcore.io.IoUtils;
    155 
    156 public class BackupManagerService extends IBackupManager.Stub {
    157 
    158     private static final String TAG = "BackupManagerService";
    159     private static final boolean DEBUG = true;
    160     private static final boolean MORE_DEBUG = false;
    161     private static final boolean DEBUG_SCHEDULING = MORE_DEBUG || true;
    162 
    163     // System-private key used for backing up an app's widget state.  Must
    164     // begin with U+FFxx by convention (we reserve all keys starting
    165     // with U+FF00 or higher for system use).
    166     static final String KEY_WIDGET_STATE = "\uffed\uffedwidget";
    167 
    168     // Historical and current algorithm names
    169     static final String PBKDF_CURRENT = "PBKDF2WithHmacSHA1";
    170     static final String PBKDF_FALLBACK = "PBKDF2WithHmacSHA1And8bit";
    171 
    172     // Name and current contents version of the full-backup manifest file
    173     //
    174     // Manifest version history:
    175     //
    176     // 1 : initial release
    177     static final String BACKUP_MANIFEST_FILENAME = "_manifest";
    178     static final int BACKUP_MANIFEST_VERSION = 1;
    179 
    180     // External archive format version history:
    181     //
    182     // 1 : initial release
    183     // 2 : no format change per se; version bump to facilitate PBKDF2 version skew detection
    184     // 3 : introduced "_meta" metadata file; no other format change per se
    185     static final int BACKUP_FILE_VERSION = 3;
    186     static final String BACKUP_FILE_HEADER_MAGIC = "ANDROID BACKUP\n";
    187     static final int BACKUP_PW_FILE_VERSION = 2;
    188     static final String BACKUP_METADATA_FILENAME = "_meta";
    189     static final int BACKUP_METADATA_VERSION = 1;
    190     static final int BACKUP_WIDGET_METADATA_TOKEN = 0x01FFED01;
    191     static final boolean COMPRESS_FULL_BACKUPS = true; // should be true in production
    192 
    193     static final String SETTINGS_PACKAGE = "com.android.providers.settings";
    194     static final String SHARED_BACKUP_AGENT_PACKAGE = "com.android.sharedstoragebackup";
    195     static final String SERVICE_ACTION_TRANSPORT_HOST = "android.backup.TRANSPORT_HOST";
    196 
    197     // How often we perform a backup pass.  Privileged external callers can
    198     // trigger an immediate pass.
    199     private static final long BACKUP_INTERVAL = AlarmManager.INTERVAL_HOUR;
    200 
    201     // Random variation in backup scheduling time to avoid server load spikes
    202     private static final int FUZZ_MILLIS = 5 * 60 * 1000;
    203 
    204     // The amount of time between the initial provisioning of the device and
    205     // the first backup pass.
    206     private static final long FIRST_BACKUP_INTERVAL = 12 * AlarmManager.INTERVAL_HOUR;
    207 
    208     // Retry interval for clear/init when the transport is unavailable
    209     private static final long TRANSPORT_RETRY_INTERVAL = 1 * AlarmManager.INTERVAL_HOUR;
    210 
    211     private static final String RUN_BACKUP_ACTION = "android.app.backup.intent.RUN";
    212     private static final String RUN_INITIALIZE_ACTION = "android.app.backup.intent.INIT";
    213     private static final String RUN_CLEAR_ACTION = "android.app.backup.intent.CLEAR";
    214     private static final int MSG_RUN_BACKUP = 1;
    215     private static final int MSG_RUN_ADB_BACKUP = 2;
    216     private static final int MSG_RUN_RESTORE = 3;
    217     private static final int MSG_RUN_CLEAR = 4;
    218     private static final int MSG_RUN_INITIALIZE = 5;
    219     private static final int MSG_RUN_GET_RESTORE_SETS = 6;
    220     private static final int MSG_TIMEOUT = 7;
    221     private static final int MSG_RESTORE_TIMEOUT = 8;
    222     private static final int MSG_FULL_CONFIRMATION_TIMEOUT = 9;
    223     private static final int MSG_RUN_ADB_RESTORE = 10;
    224     private static final int MSG_RETRY_INIT = 11;
    225     private static final int MSG_RETRY_CLEAR = 12;
    226     private static final int MSG_WIDGET_BROADCAST = 13;
    227     private static final int MSG_RUN_FULL_TRANSPORT_BACKUP = 14;
    228 
    229     // backup task state machine tick
    230     static final int MSG_BACKUP_RESTORE_STEP = 20;
    231     static final int MSG_OP_COMPLETE = 21;
    232 
    233     // Timeout interval for deciding that a bind or clear-data has taken too long
    234     static final long TIMEOUT_INTERVAL = 10 * 1000;
    235 
    236     // Timeout intervals for agent backup & restore operations
    237     static final long TIMEOUT_BACKUP_INTERVAL = 30 * 1000;
    238     static final long TIMEOUT_FULL_BACKUP_INTERVAL = 5 * 60 * 1000;
    239     static final long TIMEOUT_SHARED_BACKUP_INTERVAL = 30 * 60 * 1000;
    240     static final long TIMEOUT_RESTORE_INTERVAL = 60 * 1000;
    241     static final long TIMEOUT_RESTORE_FINISHED_INTERVAL = 30 * 1000;
    242 
    243     // User confirmation timeout for a full backup/restore operation.  It's this long in
    244     // order to give them time to enter the backup password.
    245     static final long TIMEOUT_FULL_CONFIRMATION = 60 * 1000;
    246 
    247     // How long between attempts to perform a full-data backup of any given app
    248     static final long MIN_FULL_BACKUP_INTERVAL = 1000 * 60 * 60 * 24; // one day
    249 
    250     Context mContext;
    251     private PackageManager mPackageManager;
    252     IPackageManager mPackageManagerBinder;
    253     private IActivityManager mActivityManager;
    254     private PowerManager mPowerManager;
    255     private AlarmManager mAlarmManager;
    256     private IMountService mMountService;
    257     IBackupManager mBackupManagerBinder;
    258 
    259     boolean mEnabled;   // access to this is synchronized on 'this'
    260     boolean mProvisioned;
    261     boolean mAutoRestore;
    262     PowerManager.WakeLock mWakelock;
    263     HandlerThread mHandlerThread;
    264     BackupHandler mBackupHandler;
    265     PendingIntent mRunBackupIntent, mRunInitIntent;
    266     BroadcastReceiver mRunBackupReceiver, mRunInitReceiver;
    267     // map UIDs to the set of participating packages under that UID
    268     final SparseArray<HashSet<String>> mBackupParticipants
    269             = new SparseArray<HashSet<String>>();
    270     // set of backup services that have pending changes
    271     class BackupRequest {
    272         public String packageName;
    273 
    274         BackupRequest(String pkgName) {
    275             packageName = pkgName;
    276         }
    277 
    278         public String toString() {
    279             return "BackupRequest{pkg=" + packageName + "}";
    280         }
    281     }
    282     // Backups that we haven't started yet.  Keys are package names.
    283     HashMap<String,BackupRequest> mPendingBackups
    284             = new HashMap<String,BackupRequest>();
    285 
    286     // Pseudoname that we use for the Package Manager metadata "package"
    287     static final String PACKAGE_MANAGER_SENTINEL = "@pm@";
    288 
    289     // locking around the pending-backup management
    290     final Object mQueueLock = new Object();
    291 
    292     // The thread performing the sequence of queued backups binds to each app's agent
    293     // in succession.  Bind notifications are asynchronously delivered through the
    294     // Activity Manager; use this lock object to signal when a requested binding has
    295     // completed.
    296     final Object mAgentConnectLock = new Object();
    297     IBackupAgent mConnectedAgent;
    298     volatile boolean mBackupRunning;
    299     volatile boolean mConnecting;
    300     volatile long mLastBackupPass;
    301     volatile long mNextBackupPass;
    302 
    303     // For debugging, we maintain a progress trace of operations during backup
    304     static final boolean DEBUG_BACKUP_TRACE = true;
    305     final List<String> mBackupTrace = new ArrayList<String>();
    306 
    307     // A similar synchronization mechanism around clearing apps' data for restore
    308     final Object mClearDataLock = new Object();
    309     volatile boolean mClearingData;
    310 
    311     // Transport bookkeeping
    312     final Intent mTransportServiceIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST);
    313     final ArrayMap<String,String> mTransportNames
    314             = new ArrayMap<String,String>();             // component name -> registration name
    315     final ArrayMap<String,IBackupTransport> mTransports
    316             = new ArrayMap<String,IBackupTransport>();   // registration name -> binder
    317     final ArrayMap<String,TransportConnection> mTransportConnections
    318             = new ArrayMap<String,TransportConnection>();
    319     String mCurrentTransport;
    320     ActiveRestoreSession mActiveRestoreSession;
    321 
    322     // Watch the device provisioning operation during setup
    323     ContentObserver mProvisionedObserver;
    324 
    325     static BackupManagerService sInstance;
    326     static BackupManagerService getInstance() {
    327         // Always constructed during system bringup, so no need to lazy-init
    328         return sInstance;
    329     }
    330 
    331     public static final class Lifecycle extends SystemService {
    332 
    333         public Lifecycle(Context context) {
    334             super(context);
    335             sInstance = new BackupManagerService(context);
    336         }
    337 
    338         @Override
    339         public void onStart() {
    340             publishBinderService(Context.BACKUP_SERVICE, sInstance);
    341         }
    342 
    343         @Override
    344         public void onBootPhase(int phase) {
    345             if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
    346                 ContentResolver r = sInstance.mContext.getContentResolver();
    347                 boolean areEnabled = Settings.Secure.getInt(r,
    348                         Settings.Secure.BACKUP_ENABLED, 0) != 0;
    349                 sInstance.setBackupEnabled(areEnabled);
    350             }
    351         }
    352     }
    353 
    354     class ProvisionedObserver extends ContentObserver {
    355         public ProvisionedObserver(Handler handler) {
    356             super(handler);
    357         }
    358 
    359         public void onChange(boolean selfChange) {
    360             final boolean wasProvisioned = mProvisioned;
    361             final boolean isProvisioned = deviceIsProvisioned();
    362             // latch: never unprovision
    363             mProvisioned = wasProvisioned || isProvisioned;
    364             if (MORE_DEBUG) {
    365                 Slog.d(TAG, "Provisioning change: was=" + wasProvisioned
    366                         + " is=" + isProvisioned + " now=" + mProvisioned);
    367             }
    368 
    369             synchronized (mQueueLock) {
    370                 if (mProvisioned && !wasProvisioned && mEnabled) {
    371                     // we're now good to go, so start the backup alarms
    372                     if (MORE_DEBUG) Slog.d(TAG, "Now provisioned, so starting backups");
    373                     startBackupAlarmsLocked(FIRST_BACKUP_INTERVAL);
    374                 }
    375             }
    376         }
    377     }
    378 
    379     class RestoreGetSetsParams {
    380         public IBackupTransport transport;
    381         public ActiveRestoreSession session;
    382         public IRestoreObserver observer;
    383 
    384         RestoreGetSetsParams(IBackupTransport _transport, ActiveRestoreSession _session,
    385                 IRestoreObserver _observer) {
    386             transport = _transport;
    387             session = _session;
    388             observer = _observer;
    389         }
    390     }
    391 
    392     class RestoreParams {
    393         public IBackupTransport transport;
    394         public String dirName;
    395         public IRestoreObserver observer;
    396         public long token;
    397         public PackageInfo pkgInfo;
    398         public int pmToken; // in post-install restore, the PM's token for this transaction
    399         public boolean isSystemRestore;
    400         public String[] filterSet;
    401 
    402         // Restore a single package
    403         RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
    404                 long _token, PackageInfo _pkg, int _pmToken) {
    405             transport = _transport;
    406             dirName = _dirName;
    407             observer = _obs;
    408             token = _token;
    409             pkgInfo = _pkg;
    410             pmToken = _pmToken;
    411             isSystemRestore = false;
    412             filterSet = null;
    413         }
    414 
    415         // Restore everything possible.  This is the form that Setup Wizard or similar
    416         // restore UXes use.
    417         RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
    418                 long _token) {
    419             transport = _transport;
    420             dirName = _dirName;
    421             observer = _obs;
    422             token = _token;
    423             pkgInfo = null;
    424             pmToken = 0;
    425             isSystemRestore = true;
    426             filterSet = null;
    427         }
    428 
    429         // Restore some set of packages.  Leave this one up to the caller to specify
    430         // whether it's to be considered a system-level restore.
    431         RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
    432                 long _token, String[] _filterSet, boolean _isSystemRestore) {
    433             transport = _transport;
    434             dirName = _dirName;
    435             observer = _obs;
    436             token = _token;
    437             pkgInfo = null;
    438             pmToken = 0;
    439             isSystemRestore = _isSystemRestore;
    440             filterSet = _filterSet;
    441         }
    442     }
    443 
    444     class ClearParams {
    445         public IBackupTransport transport;
    446         public PackageInfo packageInfo;
    447 
    448         ClearParams(IBackupTransport _transport, PackageInfo _info) {
    449             transport = _transport;
    450             packageInfo = _info;
    451         }
    452     }
    453 
    454     class ClearRetryParams {
    455         public String transportName;
    456         public String packageName;
    457 
    458         ClearRetryParams(String transport, String pkg) {
    459             transportName = transport;
    460             packageName = pkg;
    461         }
    462     }
    463 
    464     class FullParams {
    465         public ParcelFileDescriptor fd;
    466         public final AtomicBoolean latch;
    467         public IFullBackupRestoreObserver observer;
    468         public String curPassword;     // filled in by the confirmation step
    469         public String encryptPassword;
    470 
    471         FullParams() {
    472             latch = new AtomicBoolean(false);
    473         }
    474     }
    475 
    476     class FullBackupParams extends FullParams {
    477         public boolean includeApks;
    478         public boolean includeObbs;
    479         public boolean includeShared;
    480         public boolean doWidgets;
    481         public boolean allApps;
    482         public boolean includeSystem;
    483         public boolean doCompress;
    484         public String[] packages;
    485 
    486         FullBackupParams(ParcelFileDescriptor output, boolean saveApks, boolean saveObbs,
    487                 boolean saveShared, boolean alsoWidgets, boolean doAllApps, boolean doSystem,
    488                 boolean compress, String[] pkgList) {
    489             fd = output;
    490             includeApks = saveApks;
    491             includeObbs = saveObbs;
    492             includeShared = saveShared;
    493             doWidgets = alsoWidgets;
    494             allApps = doAllApps;
    495             includeSystem = doSystem;
    496             doCompress = compress;
    497             packages = pkgList;
    498         }
    499     }
    500 
    501     class FullRestoreParams extends FullParams {
    502         FullRestoreParams(ParcelFileDescriptor input) {
    503             fd = input;
    504         }
    505     }
    506 
    507     // Bookkeeping of in-flight operations for timeout etc. purposes.  The operation
    508     // token is the index of the entry in the pending-operations list.
    509     static final int OP_PENDING = 0;
    510     static final int OP_ACKNOWLEDGED = 1;
    511     static final int OP_TIMEOUT = -1;
    512 
    513     class Operation {
    514         public int state;
    515         public BackupRestoreTask callback;
    516 
    517         Operation(int initialState, BackupRestoreTask callbackObj) {
    518             state = initialState;
    519             callback = callbackObj;
    520         }
    521     }
    522     final SparseArray<Operation> mCurrentOperations = new SparseArray<Operation>();
    523     final Object mCurrentOpLock = new Object();
    524     final Random mTokenGenerator = new Random();
    525 
    526     final SparseArray<FullParams> mFullConfirmations = new SparseArray<FullParams>();
    527 
    528     // Where we keep our journal files and other bookkeeping
    529     File mBaseStateDir;
    530     File mDataDir;
    531     File mJournalDir;
    532     File mJournal;
    533 
    534     // Backup password, if any, and the file where it's saved.  What is stored is not the
    535     // password text itself; it's the result of a PBKDF2 hash with a randomly chosen (but
    536     // persisted) salt.  Validation is performed by running the challenge text through the
    537     // same PBKDF2 cycle with the persisted salt; if the resulting derived key string matches
    538     // the saved hash string, then the challenge text matches the originally supplied
    539     // password text.
    540     private final SecureRandom mRng = new SecureRandom();
    541     private String mPasswordHash;
    542     private File mPasswordHashFile;
    543     private int mPasswordVersion;
    544     private File mPasswordVersionFile;
    545     private byte[] mPasswordSalt;
    546 
    547     // Configuration of PBKDF2 that we use for generating pw hashes and intermediate keys
    548     static final int PBKDF2_HASH_ROUNDS = 10000;
    549     static final int PBKDF2_KEY_SIZE = 256;     // bits
    550     static final int PBKDF2_SALT_SIZE = 512;    // bits
    551     static final String ENCRYPTION_ALGORITHM_NAME = "AES-256";
    552 
    553     // Keep a log of all the apps we've ever backed up, and what the
    554     // dataset tokens are for both the current backup dataset and
    555     // the ancestral dataset.
    556     private File mEverStored;
    557     HashSet<String> mEverStoredApps = new HashSet<String>();
    558 
    559     static final int CURRENT_ANCESTRAL_RECORD_VERSION = 1;  // increment when the schema changes
    560     File mTokenFile;
    561     Set<String> mAncestralPackages = null;
    562     long mAncestralToken = 0;
    563     long mCurrentToken = 0;
    564 
    565     // Persistently track the need to do a full init
    566     static final String INIT_SENTINEL_FILE_NAME = "_need_init_";
    567     HashSet<String> mPendingInits = new HashSet<String>();  // transport names
    568 
    569     // Round-robin queue for scheduling full backup passes
    570     static final int SCHEDULE_FILE_VERSION = 1; // current version of the schedule file
    571     class FullBackupEntry implements Comparable<FullBackupEntry> {
    572         String packageName;
    573         long lastBackup;
    574 
    575         FullBackupEntry(String pkg, long when) {
    576             packageName = pkg;
    577             lastBackup = when;
    578         }
    579 
    580         @Override
    581         public int compareTo(FullBackupEntry other) {
    582             if (lastBackup < other.lastBackup) return -1;
    583             else if (lastBackup > other.lastBackup) return 1;
    584             else return 0;
    585         }
    586     }
    587 
    588     File mFullBackupScheduleFile;
    589     // If we're running a schedule-driven full backup, this is the task instance doing it
    590     PerformFullTransportBackupTask mRunningFullBackupTask; // inside mQueueLock
    591     ArrayList<FullBackupEntry> mFullBackupQueue;           // inside mQueueLock
    592 
    593     // Utility: build a new random integer token
    594     int generateToken() {
    595         int token;
    596         do {
    597             synchronized (mTokenGenerator) {
    598                 token = mTokenGenerator.nextInt();
    599             }
    600         } while (token < 0);
    601         return token;
    602     }
    603 
    604     // High level policy: apps are ineligible for backup if certain conditions apply
    605     public static boolean appIsEligibleForBackup(ApplicationInfo app) {
    606         // 1. their manifest states android:allowBackup="false"
    607         if ((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) {
    608             return false;
    609         }
    610 
    611         // 2. they run as a system-level uid but do not supply their own backup agent
    612         if ((app.uid < Process.FIRST_APPLICATION_UID) && (app.backupAgentName == null)) {
    613             return false;
    614         }
    615 
    616         // 3. it is the special shared-storage backup package used for 'adb backup'
    617         if (app.packageName.equals(BackupManagerService.SHARED_BACKUP_AGENT_PACKAGE)) {
    618             return false;
    619         }
    620 
    621         return true;
    622     }
    623 
    624     /* does *not* check overall backup eligibility policy! */
    625     public static boolean appGetsFullBackup(PackageInfo pkg) {
    626         if (pkg.applicationInfo.backupAgentName != null) {
    627             // If it has an agent, it gets full backups only if it says so
    628             return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_FULL_BACKUP_ONLY) != 0;
    629         }
    630 
    631         // No agent means we do full backups for it
    632         return true;
    633     }
    634 
    635     // ----- Asynchronous backup/restore handler thread -----
    636 
    637     private class BackupHandler extends Handler {
    638         public BackupHandler(Looper looper) {
    639             super(looper);
    640         }
    641 
    642         public void handleMessage(Message msg) {
    643 
    644             switch (msg.what) {
    645             case MSG_RUN_BACKUP:
    646             {
    647                 mLastBackupPass = System.currentTimeMillis();
    648                 mNextBackupPass = mLastBackupPass + BACKUP_INTERVAL;
    649 
    650                 IBackupTransport transport = getTransport(mCurrentTransport);
    651                 if (transport == null) {
    652                     Slog.v(TAG, "Backup requested but no transport available");
    653                     synchronized (mQueueLock) {
    654                         mBackupRunning = false;
    655                     }
    656                     mWakelock.release();
    657                     break;
    658                 }
    659 
    660                 // snapshot the pending-backup set and work on that
    661                 ArrayList<BackupRequest> queue = new ArrayList<BackupRequest>();
    662                 File oldJournal = mJournal;
    663                 synchronized (mQueueLock) {
    664                     // Do we have any work to do?  Construct the work queue
    665                     // then release the synchronization lock to actually run
    666                     // the backup.
    667                     if (mPendingBackups.size() > 0) {
    668                         for (BackupRequest b: mPendingBackups.values()) {
    669                             queue.add(b);
    670                         }
    671                         if (DEBUG) Slog.v(TAG, "clearing pending backups");
    672                         mPendingBackups.clear();
    673 
    674                         // Start a new backup-queue journal file too
    675                         mJournal = null;
    676 
    677                     }
    678                 }
    679 
    680                 // At this point, we have started a new journal file, and the old
    681                 // file identity is being passed to the backup processing task.
    682                 // When it completes successfully, that old journal file will be
    683                 // deleted.  If we crash prior to that, the old journal is parsed
    684                 // at next boot and the journaled requests fulfilled.
    685                 boolean staged = true;
    686                 if (queue.size() > 0) {
    687                     // Spin up a backup state sequence and set it running
    688                     try {
    689                         String dirName = transport.transportDirName();
    690                         PerformBackupTask pbt = new PerformBackupTask(transport, dirName,
    691                                 queue, oldJournal);
    692                         Message pbtMessage = obtainMessage(MSG_BACKUP_RESTORE_STEP, pbt);
    693                         sendMessage(pbtMessage);
    694                     } catch (RemoteException e) {
    695                         // unable to ask the transport its dir name -- transient failure, since
    696                         // the above check succeeded.  Try again next time.
    697                         Slog.e(TAG, "Transport became unavailable attempting backup");
    698                         staged = false;
    699                     }
    700                 } else {
    701                     Slog.v(TAG, "Backup requested but nothing pending");
    702                     staged = false;
    703                 }
    704 
    705                 if (!staged) {
    706                     // if we didn't actually hand off the wakelock, rewind until next time
    707                     synchronized (mQueueLock) {
    708                         mBackupRunning = false;
    709                     }
    710                     mWakelock.release();
    711                 }
    712                 break;
    713             }
    714 
    715             case MSG_BACKUP_RESTORE_STEP:
    716             {
    717                 try {
    718                     BackupRestoreTask task = (BackupRestoreTask) msg.obj;
    719                     if (MORE_DEBUG) Slog.v(TAG, "Got next step for " + task + ", executing");
    720                     task.execute();
    721                 } catch (ClassCastException e) {
    722                     Slog.e(TAG, "Invalid backup task in flight, obj=" + msg.obj);
    723                 }
    724                 break;
    725             }
    726 
    727             case MSG_OP_COMPLETE:
    728             {
    729                 try {
    730                     BackupRestoreTask task = (BackupRestoreTask) msg.obj;
    731                     task.operationComplete();
    732                 } catch (ClassCastException e) {
    733                     Slog.e(TAG, "Invalid completion in flight, obj=" + msg.obj);
    734                 }
    735                 break;
    736             }
    737 
    738             case MSG_RUN_ADB_BACKUP:
    739             {
    740                 // TODO: refactor full backup to be a looper-based state machine
    741                 // similar to normal backup/restore.
    742                 FullBackupParams params = (FullBackupParams)msg.obj;
    743                 PerformAdbBackupTask task = new PerformAdbBackupTask(params.fd,
    744                         params.observer, params.includeApks, params.includeObbs,
    745                         params.includeShared, params.doWidgets,
    746                         params.curPassword, params.encryptPassword,
    747                         params.allApps, params.includeSystem, params.doCompress,
    748                         params.packages, params.latch);
    749                 (new Thread(task, "adb-backup")).start();
    750                 break;
    751             }
    752 
    753             case MSG_RUN_FULL_TRANSPORT_BACKUP:
    754             {
    755                 PerformFullTransportBackupTask task = (PerformFullTransportBackupTask) msg.obj;
    756                 (new Thread(task, "transport-backup")).start();
    757                 break;
    758             }
    759 
    760             case MSG_RUN_RESTORE:
    761             {
    762                 RestoreParams params = (RestoreParams)msg.obj;
    763                 Slog.d(TAG, "MSG_RUN_RESTORE observer=" + params.observer);
    764                 BackupRestoreTask task = new PerformUnifiedRestoreTask(params.transport,
    765                         params.observer, params.token, params.pkgInfo, params.pmToken,
    766                         params.isSystemRestore, params.filterSet);
    767                 Message restoreMsg = obtainMessage(MSG_BACKUP_RESTORE_STEP, task);
    768                 sendMessage(restoreMsg);
    769                 break;
    770             }
    771 
    772             case MSG_RUN_ADB_RESTORE:
    773             {
    774                 // TODO: refactor full restore to be a looper-based state machine
    775                 // similar to normal backup/restore.
    776                 FullRestoreParams params = (FullRestoreParams)msg.obj;
    777                 PerformAdbRestoreTask task = new PerformAdbRestoreTask(params.fd,
    778                         params.curPassword, params.encryptPassword,
    779                         params.observer, params.latch);
    780                 (new Thread(task, "adb-restore")).start();
    781                 break;
    782             }
    783 
    784             case MSG_RUN_CLEAR:
    785             {
    786                 ClearParams params = (ClearParams)msg.obj;
    787                 (new PerformClearTask(params.transport, params.packageInfo)).run();
    788                 break;
    789             }
    790 
    791             case MSG_RETRY_CLEAR:
    792             {
    793                 // reenqueues if the transport remains unavailable
    794                 ClearRetryParams params = (ClearRetryParams)msg.obj;
    795                 clearBackupData(params.transportName, params.packageName);
    796                 break;
    797             }
    798 
    799             case MSG_RUN_INITIALIZE:
    800             {
    801                 HashSet<String> queue;
    802 
    803                 // Snapshot the pending-init queue and work on that
    804                 synchronized (mQueueLock) {
    805                     queue = new HashSet<String>(mPendingInits);
    806                     mPendingInits.clear();
    807                 }
    808 
    809                 (new PerformInitializeTask(queue)).run();
    810                 break;
    811             }
    812 
    813             case MSG_RETRY_INIT:
    814             {
    815                 synchronized (mQueueLock) {
    816                     recordInitPendingLocked(msg.arg1 != 0, (String)msg.obj);
    817                     mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
    818                             mRunInitIntent);
    819                 }
    820                 break;
    821             }
    822 
    823             case MSG_RUN_GET_RESTORE_SETS:
    824             {
    825                 // Like other async operations, this is entered with the wakelock held
    826                 RestoreSet[] sets = null;
    827                 RestoreGetSetsParams params = (RestoreGetSetsParams)msg.obj;
    828                 try {
    829                     sets = params.transport.getAvailableRestoreSets();
    830                     // cache the result in the active session
    831                     synchronized (params.session) {
    832                         params.session.mRestoreSets = sets;
    833                     }
    834                     if (sets == null) EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
    835                 } catch (Exception e) {
    836                     Slog.e(TAG, "Error from transport getting set list");
    837                 } finally {
    838                     if (params.observer != null) {
    839                         try {
    840                             params.observer.restoreSetsAvailable(sets);
    841                         } catch (RemoteException re) {
    842                             Slog.e(TAG, "Unable to report listing to observer");
    843                         } catch (Exception e) {
    844                             Slog.e(TAG, "Restore observer threw", e);
    845                         }
    846                     }
    847 
    848                     // Done: reset the session timeout clock
    849                     removeMessages(MSG_RESTORE_TIMEOUT);
    850                     sendEmptyMessageDelayed(MSG_RESTORE_TIMEOUT, TIMEOUT_RESTORE_INTERVAL);
    851 
    852                     mWakelock.release();
    853                 }
    854                 break;
    855             }
    856 
    857             case MSG_TIMEOUT:
    858             {
    859                 handleTimeout(msg.arg1, msg.obj);
    860                 break;
    861             }
    862 
    863             case MSG_RESTORE_TIMEOUT:
    864             {
    865                 synchronized (BackupManagerService.this) {
    866                     if (mActiveRestoreSession != null) {
    867                         // Client app left the restore session dangling.  We know that it
    868                         // can't be in the middle of an actual restore operation because
    869                         // the timeout is suspended while a restore is in progress.  Clean
    870                         // up now.
    871                         Slog.w(TAG, "Restore session timed out; aborting");
    872                         mActiveRestoreSession.markTimedOut();
    873                         post(mActiveRestoreSession.new EndRestoreRunnable(
    874                                 BackupManagerService.this, mActiveRestoreSession));
    875                     }
    876                 }
    877                 break;
    878             }
    879 
    880             case MSG_FULL_CONFIRMATION_TIMEOUT:
    881             {
    882                 synchronized (mFullConfirmations) {
    883                     FullParams params = mFullConfirmations.get(msg.arg1);
    884                     if (params != null) {
    885                         Slog.i(TAG, "Full backup/restore timed out waiting for user confirmation");
    886 
    887                         // Release the waiter; timeout == completion
    888                         signalFullBackupRestoreCompletion(params);
    889 
    890                         // Remove the token from the set
    891                         mFullConfirmations.delete(msg.arg1);
    892 
    893                         // Report a timeout to the observer, if any
    894                         if (params.observer != null) {
    895                             try {
    896                                 params.observer.onTimeout();
    897                             } catch (RemoteException e) {
    898                                 /* don't care if the app has gone away */
    899                             }
    900                         }
    901                     } else {
    902                         Slog.d(TAG, "couldn't find params for token " + msg.arg1);
    903                     }
    904                 }
    905                 break;
    906             }
    907 
    908             case MSG_WIDGET_BROADCAST:
    909             {
    910                 final Intent intent = (Intent) msg.obj;
    911                 mContext.sendBroadcastAsUser(intent, UserHandle.OWNER);
    912                 break;
    913             }
    914             }
    915         }
    916     }
    917 
    918     // ----- Debug-only backup operation trace -----
    919     void addBackupTrace(String s) {
    920         if (DEBUG_BACKUP_TRACE) {
    921             synchronized (mBackupTrace) {
    922                 mBackupTrace.add(s);
    923             }
    924         }
    925     }
    926 
    927     void clearBackupTrace() {
    928         if (DEBUG_BACKUP_TRACE) {
    929             synchronized (mBackupTrace) {
    930                 mBackupTrace.clear();
    931             }
    932         }
    933     }
    934 
    935     // ----- Main service implementation -----
    936 
    937     public BackupManagerService(Context context) {
    938         mContext = context;
    939         mPackageManager = context.getPackageManager();
    940         mPackageManagerBinder = AppGlobals.getPackageManager();
    941         mActivityManager = ActivityManagerNative.getDefault();
    942 
    943         mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    944         mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
    945         mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
    946 
    947         mBackupManagerBinder = asInterface(asBinder());
    948 
    949         // spin up the backup/restore handler thread
    950         mHandlerThread = new HandlerThread("backup", Process.THREAD_PRIORITY_BACKGROUND);
    951         mHandlerThread.start();
    952         mBackupHandler = new BackupHandler(mHandlerThread.getLooper());
    953 
    954         // Set up our bookkeeping
    955         final ContentResolver resolver = context.getContentResolver();
    956         mProvisioned = Settings.Global.getInt(resolver,
    957                 Settings.Global.DEVICE_PROVISIONED, 0) != 0;
    958         mAutoRestore = Settings.Secure.getInt(resolver,
    959                 Settings.Secure.BACKUP_AUTO_RESTORE, 1) != 0;
    960 
    961         mProvisionedObserver = new ProvisionedObserver(mBackupHandler);
    962         resolver.registerContentObserver(
    963                 Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED),
    964                 false, mProvisionedObserver);
    965 
    966         // If Encrypted file systems is enabled or disabled, this call will return the
    967         // correct directory.
    968         mBaseStateDir = new File(Environment.getSecureDataDirectory(), "backup");
    969         mBaseStateDir.mkdirs();
    970         if (!SELinux.restorecon(mBaseStateDir)) {
    971             Slog.e(TAG, "SELinux restorecon failed on " + mBaseStateDir);
    972         }
    973         mDataDir = Environment.getDownloadCacheDirectory();
    974 
    975         mPasswordVersion = 1;       // unless we hear otherwise
    976         mPasswordVersionFile = new File(mBaseStateDir, "pwversion");
    977         if (mPasswordVersionFile.exists()) {
    978             FileInputStream fin = null;
    979             DataInputStream in = null;
    980             try {
    981                 fin = new FileInputStream(mPasswordVersionFile);
    982                 in = new DataInputStream(fin);
    983                 mPasswordVersion = in.readInt();
    984             } catch (IOException e) {
    985                 Slog.e(TAG, "Unable to read backup pw version");
    986             } finally {
    987                 try {
    988                     if (in != null) in.close();
    989                     if (fin != null) fin.close();
    990                 } catch (IOException e) {
    991                     Slog.w(TAG, "Error closing pw version files");
    992                 }
    993             }
    994         }
    995 
    996         mPasswordHashFile = new File(mBaseStateDir, "pwhash");
    997         if (mPasswordHashFile.exists()) {
    998             FileInputStream fin = null;
    999             DataInputStream in = null;
   1000             try {
   1001                 fin = new FileInputStream(mPasswordHashFile);
   1002                 in = new DataInputStream(new BufferedInputStream(fin));
   1003                 // integer length of the salt array, followed by the salt,
   1004                 // then the hex pw hash string
   1005                 int saltLen = in.readInt();
   1006                 byte[] salt = new byte[saltLen];
   1007                 in.readFully(salt);
   1008                 mPasswordHash = in.readUTF();
   1009                 mPasswordSalt = salt;
   1010             } catch (IOException e) {
   1011                 Slog.e(TAG, "Unable to read saved backup pw hash");
   1012             } finally {
   1013                 try {
   1014                     if (in != null) in.close();
   1015                     if (fin != null) fin.close();
   1016                 } catch (IOException e) {
   1017                     Slog.w(TAG, "Unable to close streams");
   1018                 }
   1019             }
   1020         }
   1021 
   1022         // Alarm receivers for scheduled backups & initialization operations
   1023         mRunBackupReceiver = new RunBackupReceiver();
   1024         IntentFilter filter = new IntentFilter();
   1025         filter.addAction(RUN_BACKUP_ACTION);
   1026         context.registerReceiver(mRunBackupReceiver, filter,
   1027                 android.Manifest.permission.BACKUP, null);
   1028 
   1029         mRunInitReceiver = new RunInitializeReceiver();
   1030         filter = new IntentFilter();
   1031         filter.addAction(RUN_INITIALIZE_ACTION);
   1032         context.registerReceiver(mRunInitReceiver, filter,
   1033                 android.Manifest.permission.BACKUP, null);
   1034 
   1035         Intent backupIntent = new Intent(RUN_BACKUP_ACTION);
   1036         backupIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
   1037         mRunBackupIntent = PendingIntent.getBroadcast(context, MSG_RUN_BACKUP, backupIntent, 0);
   1038 
   1039         Intent initIntent = new Intent(RUN_INITIALIZE_ACTION);
   1040         backupIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
   1041         mRunInitIntent = PendingIntent.getBroadcast(context, MSG_RUN_INITIALIZE, initIntent, 0);
   1042 
   1043         // Set up the backup-request journaling
   1044         mJournalDir = new File(mBaseStateDir, "pending");
   1045         mJournalDir.mkdirs();   // creates mBaseStateDir along the way
   1046         mJournal = null;        // will be created on first use
   1047 
   1048         // Set up the various sorts of package tracking we do
   1049         mFullBackupScheduleFile = new File(mBaseStateDir, "fb-schedule");
   1050         initPackageTracking();
   1051 
   1052         // Build our mapping of uid to backup client services.  This implicitly
   1053         // schedules a backup pass on the Package Manager metadata the first
   1054         // time anything needs to be backed up.
   1055         synchronized (mBackupParticipants) {
   1056             addPackageParticipantsLocked(null);
   1057         }
   1058 
   1059         // Set up our transport options and initialize the default transport
   1060         // TODO: Don't create transports that we don't need to?
   1061         mCurrentTransport = Settings.Secure.getString(context.getContentResolver(),
   1062                 Settings.Secure.BACKUP_TRANSPORT);
   1063         if ("".equals(mCurrentTransport)) {
   1064             mCurrentTransport = null;
   1065         }
   1066         if (DEBUG) Slog.v(TAG, "Starting with transport " + mCurrentTransport);
   1067 
   1068         // Find all transport hosts and bind to their services
   1069         List<ResolveInfo> hosts = mPackageManager.queryIntentServicesAsUser(
   1070                 mTransportServiceIntent, 0, UserHandle.USER_OWNER);
   1071         if (DEBUG) {
   1072             Slog.v(TAG, "Found transports: " + ((hosts == null) ? "null" : hosts.size()));
   1073         }
   1074         if (hosts != null) {
   1075             for (int i = 0; i < hosts.size(); i++) {
   1076                 final ServiceInfo transport = hosts.get(i).serviceInfo;
   1077                 if (MORE_DEBUG) {
   1078                     Slog.v(TAG, "   " + transport.packageName + "/" + transport.name);
   1079                 }
   1080                 tryBindTransport(transport);
   1081             }
   1082         }
   1083 
   1084         // Now that we know about valid backup participants, parse any
   1085         // leftover journal files into the pending backup set
   1086         parseLeftoverJournals();
   1087 
   1088         // Power management
   1089         mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*");
   1090     }
   1091 
   1092     private class RunBackupReceiver extends BroadcastReceiver {
   1093         public void onReceive(Context context, Intent intent) {
   1094             if (RUN_BACKUP_ACTION.equals(intent.getAction())) {
   1095                 synchronized (mQueueLock) {
   1096                     if (mPendingInits.size() > 0) {
   1097                         // If there are pending init operations, we process those
   1098                         // and then settle into the usual periodic backup schedule.
   1099                         if (DEBUG) Slog.v(TAG, "Init pending at scheduled backup");
   1100                         try {
   1101                             mAlarmManager.cancel(mRunInitIntent);
   1102                             mRunInitIntent.send();
   1103                         } catch (PendingIntent.CanceledException ce) {
   1104                             Slog.e(TAG, "Run init intent cancelled");
   1105                             // can't really do more than bail here
   1106                         }
   1107                     } else {
   1108                         // Don't run backups now if we're disabled or not yet
   1109                         // fully set up.
   1110                         if (mEnabled && mProvisioned) {
   1111                             if (!mBackupRunning) {
   1112                                 if (DEBUG) Slog.v(TAG, "Running a backup pass");
   1113 
   1114                                 // Acquire the wakelock and pass it to the backup thread.  it will
   1115                                 // be released once backup concludes.
   1116                                 mBackupRunning = true;
   1117                                 mWakelock.acquire();
   1118 
   1119                                 Message msg = mBackupHandler.obtainMessage(MSG_RUN_BACKUP);
   1120                                 mBackupHandler.sendMessage(msg);
   1121                             } else {
   1122                                 Slog.i(TAG, "Backup time but one already running");
   1123                             }
   1124                         } else {
   1125                             Slog.w(TAG, "Backup pass but e=" + mEnabled + " p=" + mProvisioned);
   1126                         }
   1127                     }
   1128                 }
   1129             }
   1130         }
   1131     }
   1132 
   1133     private class RunInitializeReceiver extends BroadcastReceiver {
   1134         public void onReceive(Context context, Intent intent) {
   1135             if (RUN_INITIALIZE_ACTION.equals(intent.getAction())) {
   1136                 synchronized (mQueueLock) {
   1137                     if (DEBUG) Slog.v(TAG, "Running a device init");
   1138 
   1139                     // Acquire the wakelock and pass it to the init thread.  it will
   1140                     // be released once init concludes.
   1141                     mWakelock.acquire();
   1142 
   1143                     Message msg = mBackupHandler.obtainMessage(MSG_RUN_INITIALIZE);
   1144                     mBackupHandler.sendMessage(msg);
   1145                 }
   1146             }
   1147         }
   1148     }
   1149 
   1150     private void initPackageTracking() {
   1151         if (MORE_DEBUG) Slog.v(TAG, "` tracking");
   1152 
   1153         // Remember our ancestral dataset
   1154         mTokenFile = new File(mBaseStateDir, "ancestral");
   1155         try {
   1156             RandomAccessFile tf = new RandomAccessFile(mTokenFile, "r");
   1157             int version = tf.readInt();
   1158             if (version == CURRENT_ANCESTRAL_RECORD_VERSION) {
   1159                 mAncestralToken = tf.readLong();
   1160                 mCurrentToken = tf.readLong();
   1161 
   1162                 int numPackages = tf.readInt();
   1163                 if (numPackages >= 0) {
   1164                     mAncestralPackages = new HashSet<String>();
   1165                     for (int i = 0; i < numPackages; i++) {
   1166                         String pkgName = tf.readUTF();
   1167                         mAncestralPackages.add(pkgName);
   1168                     }
   1169                 }
   1170             }
   1171             tf.close();
   1172         } catch (FileNotFoundException fnf) {
   1173             // Probably innocuous
   1174             Slog.v(TAG, "No ancestral data");
   1175         } catch (IOException e) {
   1176             Slog.w(TAG, "Unable to read token file", e);
   1177         }
   1178 
   1179         // Keep a log of what apps we've ever backed up.  Because we might have
   1180         // rebooted in the middle of an operation that was removing something from
   1181         // this log, we sanity-check its contents here and reconstruct it.
   1182         mEverStored = new File(mBaseStateDir, "processed");
   1183         File tempProcessedFile = new File(mBaseStateDir, "processed.new");
   1184 
   1185         // If we were in the middle of removing something from the ever-backed-up
   1186         // file, there might be a transient "processed.new" file still present.
   1187         // Ignore it -- we'll validate "processed" against the current package set.
   1188         if (tempProcessedFile.exists()) {
   1189             tempProcessedFile.delete();
   1190         }
   1191 
   1192         // If there are previous contents, parse them out then start a new
   1193         // file to continue the recordkeeping.
   1194         if (mEverStored.exists()) {
   1195             RandomAccessFile temp = null;
   1196             RandomAccessFile in = null;
   1197 
   1198             try {
   1199                 temp = new RandomAccessFile(tempProcessedFile, "rws");
   1200                 in = new RandomAccessFile(mEverStored, "r");
   1201 
   1202                 while (true) {
   1203                     PackageInfo info;
   1204                     String pkg = in.readUTF();
   1205                     try {
   1206                         info = mPackageManager.getPackageInfo(pkg, 0);
   1207                         mEverStoredApps.add(pkg);
   1208                         temp.writeUTF(pkg);
   1209                         if (MORE_DEBUG) Slog.v(TAG, "   + " + pkg);
   1210                     } catch (NameNotFoundException e) {
   1211                         // nope, this package was uninstalled; don't include it
   1212                         if (MORE_DEBUG) Slog.v(TAG, "   - " + pkg);
   1213                     }
   1214                 }
   1215             } catch (EOFException e) {
   1216                 // Once we've rewritten the backup history log, atomically replace the
   1217                 // old one with the new one then reopen the file for continuing use.
   1218                 if (!tempProcessedFile.renameTo(mEverStored)) {
   1219                     Slog.e(TAG, "Error renaming " + tempProcessedFile + " to " + mEverStored);
   1220                 }
   1221             } catch (IOException e) {
   1222                 Slog.e(TAG, "Error in processed file", e);
   1223             } finally {
   1224                 try { if (temp != null) temp.close(); } catch (IOException e) {}
   1225                 try { if (in != null) in.close(); } catch (IOException e) {}
   1226             }
   1227         }
   1228 
   1229         // Resume the full-data backup queue
   1230         mFullBackupQueue = readFullBackupSchedule();
   1231 
   1232         // Register for broadcasts about package install, etc., so we can
   1233         // update the provider list.
   1234         IntentFilter filter = new IntentFilter();
   1235         filter.addAction(Intent.ACTION_PACKAGE_ADDED);
   1236         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
   1237         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
   1238         filter.addDataScheme("package");
   1239         mContext.registerReceiver(mBroadcastReceiver, filter);
   1240         // Register for events related to sdcard installation.
   1241         IntentFilter sdFilter = new IntentFilter();
   1242         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
   1243         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
   1244         mContext.registerReceiver(mBroadcastReceiver, sdFilter);
   1245     }
   1246 
   1247     private ArrayList<FullBackupEntry> readFullBackupSchedule() {
   1248         ArrayList<FullBackupEntry> schedule = null;
   1249         synchronized (mQueueLock) {
   1250             if (mFullBackupScheduleFile.exists()) {
   1251                 FileInputStream fstream = null;
   1252                 BufferedInputStream bufStream = null;
   1253                 DataInputStream in = null;
   1254                 try {
   1255                     fstream = new FileInputStream(mFullBackupScheduleFile);
   1256                     bufStream = new BufferedInputStream(fstream);
   1257                     in = new DataInputStream(bufStream);
   1258 
   1259                     int version = in.readInt();
   1260                     if (version != SCHEDULE_FILE_VERSION) {
   1261                         Slog.e(TAG, "Unknown backup schedule version " + version);
   1262                         return null;
   1263                     }
   1264 
   1265                     int N = in.readInt();
   1266                     schedule = new ArrayList<FullBackupEntry>(N);
   1267                     for (int i = 0; i < N; i++) {
   1268                         String pkgName = in.readUTF();
   1269                         long lastBackup = in.readLong();
   1270                         schedule.add(new FullBackupEntry(pkgName, lastBackup));
   1271                     }
   1272                     Collections.sort(schedule);
   1273                 } catch (Exception e) {
   1274                     Slog.e(TAG, "Unable to read backup schedule", e);
   1275                     mFullBackupScheduleFile.delete();
   1276                     schedule = null;
   1277                 } finally {
   1278                     IoUtils.closeQuietly(in);
   1279                     IoUtils.closeQuietly(bufStream);
   1280                     IoUtils.closeQuietly(fstream);
   1281                 }
   1282             }
   1283 
   1284             if (schedule == null) {
   1285                 // no prior queue record, or unable to read it.  Set up the queue
   1286                 // from scratch.
   1287                 List<PackageInfo> apps =
   1288                         PackageManagerBackupAgent.getStorableApplications(mPackageManager);
   1289                 final int N = apps.size();
   1290                 schedule = new ArrayList<FullBackupEntry>(N);
   1291                 for (int i = 0; i < N; i++) {
   1292                     PackageInfo info = apps.get(i);
   1293                     if (appGetsFullBackup(info)) {
   1294                         schedule.add(new FullBackupEntry(info.packageName, 0));
   1295                     }
   1296                 }
   1297                 writeFullBackupScheduleAsync();
   1298             }
   1299         }
   1300         return schedule;
   1301     }
   1302 
   1303     Runnable mFullBackupScheduleWriter = new Runnable() {
   1304         @Override public void run() {
   1305             synchronized (mQueueLock) {
   1306                 try {
   1307                     ByteArrayOutputStream bufStream = new ByteArrayOutputStream(4096);
   1308                     DataOutputStream bufOut = new DataOutputStream(bufStream);
   1309                     bufOut.writeInt(SCHEDULE_FILE_VERSION);
   1310 
   1311                     // version 1:
   1312                     //
   1313                     // [int] # of packages in the queue = N
   1314                     // N * {
   1315                     //     [utf8] package name
   1316                     //     [long] last backup time for this package
   1317                     //     }
   1318                     int N = mFullBackupQueue.size();
   1319                     bufOut.writeInt(N);
   1320 
   1321                     for (int i = 0; i < N; i++) {
   1322                         FullBackupEntry entry = mFullBackupQueue.get(i);
   1323                         bufOut.writeUTF(entry.packageName);
   1324                         bufOut.writeLong(entry.lastBackup);
   1325                     }
   1326                     bufOut.flush();
   1327 
   1328                     AtomicFile af = new AtomicFile(mFullBackupScheduleFile);
   1329                     FileOutputStream out = af.startWrite();
   1330                     out.write(bufStream.toByteArray());
   1331                     af.finishWrite(out);
   1332                 } catch (Exception e) {
   1333                     Slog.e(TAG, "Unable to write backup schedule!", e);
   1334                 }
   1335             }
   1336         }
   1337     };
   1338 
   1339     private void writeFullBackupScheduleAsync() {
   1340         mBackupHandler.removeCallbacks(mFullBackupScheduleWriter);
   1341         mBackupHandler.post(mFullBackupScheduleWriter);
   1342     }
   1343 
   1344     private void parseLeftoverJournals() {
   1345         for (File f : mJournalDir.listFiles()) {
   1346             if (mJournal == null || f.compareTo(mJournal) != 0) {
   1347                 // This isn't the current journal, so it must be a leftover.  Read
   1348                 // out the package names mentioned there and schedule them for
   1349                 // backup.
   1350                 RandomAccessFile in = null;
   1351                 try {
   1352                     Slog.i(TAG, "Found stale backup journal, scheduling");
   1353                     in = new RandomAccessFile(f, "r");
   1354                     while (true) {
   1355                         String packageName = in.readUTF();
   1356                         if (MORE_DEBUG) Slog.i(TAG, "  " + packageName);
   1357                         dataChangedImpl(packageName);
   1358                     }
   1359                 } catch (EOFException e) {
   1360                     // no more data; we're done
   1361                 } catch (Exception e) {
   1362                     Slog.e(TAG, "Can't read " + f, e);
   1363                 } finally {
   1364                     // close/delete the file
   1365                     try { if (in != null) in.close(); } catch (IOException e) {}
   1366                     f.delete();
   1367                 }
   1368             }
   1369         }
   1370     }
   1371 
   1372     private SecretKey buildPasswordKey(String algorithm, String pw, byte[] salt, int rounds) {
   1373         return buildCharArrayKey(algorithm, pw.toCharArray(), salt, rounds);
   1374     }
   1375 
   1376     private SecretKey buildCharArrayKey(String algorithm, char[] pwArray, byte[] salt, int rounds) {
   1377         try {
   1378             SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm);
   1379             KeySpec ks = new PBEKeySpec(pwArray, salt, rounds, PBKDF2_KEY_SIZE);
   1380             return keyFactory.generateSecret(ks);
   1381         } catch (InvalidKeySpecException e) {
   1382             Slog.e(TAG, "Invalid key spec for PBKDF2!");
   1383         } catch (NoSuchAlgorithmException e) {
   1384             Slog.e(TAG, "PBKDF2 unavailable!");
   1385         }
   1386         return null;
   1387     }
   1388 
   1389     private String buildPasswordHash(String algorithm, String pw, byte[] salt, int rounds) {
   1390         SecretKey key = buildPasswordKey(algorithm, pw, salt, rounds);
   1391         if (key != null) {
   1392             return byteArrayToHex(key.getEncoded());
   1393         }
   1394         return null;
   1395     }
   1396 
   1397     private String byteArrayToHex(byte[] data) {
   1398         StringBuilder buf = new StringBuilder(data.length * 2);
   1399         for (int i = 0; i < data.length; i++) {
   1400             buf.append(Byte.toHexString(data[i], true));
   1401         }
   1402         return buf.toString();
   1403     }
   1404 
   1405     private byte[] hexToByteArray(String digits) {
   1406         final int bytes = digits.length() / 2;
   1407         if (2*bytes != digits.length()) {
   1408             throw new IllegalArgumentException("Hex string must have an even number of digits");
   1409         }
   1410 
   1411         byte[] result = new byte[bytes];
   1412         for (int i = 0; i < digits.length(); i += 2) {
   1413             result[i/2] = (byte) Integer.parseInt(digits.substring(i, i+2), 16);
   1414         }
   1415         return result;
   1416     }
   1417 
   1418     private byte[] makeKeyChecksum(String algorithm, byte[] pwBytes, byte[] salt, int rounds) {
   1419         char[] mkAsChar = new char[pwBytes.length];
   1420         for (int i = 0; i < pwBytes.length; i++) {
   1421             mkAsChar[i] = (char) pwBytes[i];
   1422         }
   1423 
   1424         Key checksum = buildCharArrayKey(algorithm, mkAsChar, salt, rounds);
   1425         return checksum.getEncoded();
   1426     }
   1427 
   1428     // Used for generating random salts or passwords
   1429     private byte[] randomBytes(int bits) {
   1430         byte[] array = new byte[bits / 8];
   1431         mRng.nextBytes(array);
   1432         return array;
   1433     }
   1434 
   1435     boolean passwordMatchesSaved(String algorithm, String candidatePw, int rounds) {
   1436         if (mPasswordHash == null) {
   1437             // no current password case -- require that 'currentPw' be null or empty
   1438             if (candidatePw == null || "".equals(candidatePw)) {
   1439                 return true;
   1440             } // else the non-empty candidate does not match the empty stored pw
   1441         } else {
   1442             // hash the stated current pw and compare to the stored one
   1443             if (candidatePw != null && candidatePw.length() > 0) {
   1444                 String currentPwHash = buildPasswordHash(algorithm, candidatePw, mPasswordSalt, rounds);
   1445                 if (mPasswordHash.equalsIgnoreCase(currentPwHash)) {
   1446                     // candidate hash matches the stored hash -- the password matches
   1447                     return true;
   1448                 }
   1449             } // else the stored pw is nonempty but the candidate is empty; no match
   1450         }
   1451         return false;
   1452     }
   1453 
   1454     @Override
   1455     public boolean setBackupPassword(String currentPw, String newPw) {
   1456         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   1457                 "setBackupPassword");
   1458 
   1459         // When processing v1 passwords we may need to try two different PBKDF2 checksum regimes
   1460         final boolean pbkdf2Fallback = (mPasswordVersion < BACKUP_PW_FILE_VERSION);
   1461 
   1462         // If the supplied pw doesn't hash to the the saved one, fail.  The password
   1463         // might be caught in the legacy crypto mismatch; verify that too.
   1464         if (!passwordMatchesSaved(PBKDF_CURRENT, currentPw, PBKDF2_HASH_ROUNDS)
   1465                 && !(pbkdf2Fallback && passwordMatchesSaved(PBKDF_FALLBACK,
   1466                         currentPw, PBKDF2_HASH_ROUNDS))) {
   1467             return false;
   1468         }
   1469 
   1470         // Snap up to current on the pw file version
   1471         mPasswordVersion = BACKUP_PW_FILE_VERSION;
   1472         FileOutputStream pwFout = null;
   1473         DataOutputStream pwOut = null;
   1474         try {
   1475             pwFout = new FileOutputStream(mPasswordVersionFile);
   1476             pwOut = new DataOutputStream(pwFout);
   1477             pwOut.writeInt(mPasswordVersion);
   1478         } catch (IOException e) {
   1479             Slog.e(TAG, "Unable to write backup pw version; password not changed");
   1480             return false;
   1481         } finally {
   1482             try {
   1483                 if (pwOut != null) pwOut.close();
   1484                 if (pwFout != null) pwFout.close();
   1485             } catch (IOException e) {
   1486                 Slog.w(TAG, "Unable to close pw version record");
   1487             }
   1488         }
   1489 
   1490         // Clearing the password is okay
   1491         if (newPw == null || newPw.isEmpty()) {
   1492             if (mPasswordHashFile.exists()) {
   1493                 if (!mPasswordHashFile.delete()) {
   1494                     // Unable to delete the old pw file, so fail
   1495                     Slog.e(TAG, "Unable to clear backup password");
   1496                     return false;
   1497                 }
   1498             }
   1499             mPasswordHash = null;
   1500             mPasswordSalt = null;
   1501             return true;
   1502         }
   1503 
   1504         try {
   1505             // Okay, build the hash of the new backup password
   1506             byte[] salt = randomBytes(PBKDF2_SALT_SIZE);
   1507             String newPwHash = buildPasswordHash(PBKDF_CURRENT, newPw, salt, PBKDF2_HASH_ROUNDS);
   1508 
   1509             OutputStream pwf = null, buffer = null;
   1510             DataOutputStream out = null;
   1511             try {
   1512                 pwf = new FileOutputStream(mPasswordHashFile);
   1513                 buffer = new BufferedOutputStream(pwf);
   1514                 out = new DataOutputStream(buffer);
   1515                 // integer length of the salt array, followed by the salt,
   1516                 // then the hex pw hash string
   1517                 out.writeInt(salt.length);
   1518                 out.write(salt);
   1519                 out.writeUTF(newPwHash);
   1520                 out.flush();
   1521                 mPasswordHash = newPwHash;
   1522                 mPasswordSalt = salt;
   1523                 return true;
   1524             } finally {
   1525                 if (out != null) out.close();
   1526                 if (buffer != null) buffer.close();
   1527                 if (pwf != null) pwf.close();
   1528             }
   1529         } catch (IOException e) {
   1530             Slog.e(TAG, "Unable to set backup password");
   1531         }
   1532         return false;
   1533     }
   1534 
   1535     @Override
   1536     public boolean hasBackupPassword() {
   1537         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   1538                 "hasBackupPassword");
   1539 
   1540         return mPasswordHash != null && mPasswordHash.length() > 0;
   1541     }
   1542 
   1543     private boolean backupPasswordMatches(String currentPw) {
   1544         if (hasBackupPassword()) {
   1545             final boolean pbkdf2Fallback = (mPasswordVersion < BACKUP_PW_FILE_VERSION);
   1546             if (!passwordMatchesSaved(PBKDF_CURRENT, currentPw, PBKDF2_HASH_ROUNDS)
   1547                     && !(pbkdf2Fallback && passwordMatchesSaved(PBKDF_FALLBACK,
   1548                             currentPw, PBKDF2_HASH_ROUNDS))) {
   1549                 if (DEBUG) Slog.w(TAG, "Backup password mismatch; aborting");
   1550                 return false;
   1551             }
   1552         }
   1553         return true;
   1554     }
   1555 
   1556     // Maintain persistent state around whether need to do an initialize operation.
   1557     // Must be called with the queue lock held.
   1558     void recordInitPendingLocked(boolean isPending, String transportName) {
   1559         if (DEBUG) Slog.i(TAG, "recordInitPendingLocked: " + isPending
   1560                 + " on transport " + transportName);
   1561         mBackupHandler.removeMessages(MSG_RETRY_INIT);
   1562 
   1563         try {
   1564             IBackupTransport transport = getTransport(transportName);
   1565             if (transport != null) {
   1566                 String transportDirName = transport.transportDirName();
   1567                 File stateDir = new File(mBaseStateDir, transportDirName);
   1568                 File initPendingFile = new File(stateDir, INIT_SENTINEL_FILE_NAME);
   1569 
   1570                 if (isPending) {
   1571                     // We need an init before we can proceed with sending backup data.
   1572                     // Record that with an entry in our set of pending inits, as well as
   1573                     // journaling it via creation of a sentinel file.
   1574                     mPendingInits.add(transportName);
   1575                     try {
   1576                         (new FileOutputStream(initPendingFile)).close();
   1577                     } catch (IOException ioe) {
   1578                         // Something is badly wrong with our permissions; just try to move on
   1579                     }
   1580                 } else {
   1581                     // No more initialization needed; wipe the journal and reset our state.
   1582                     initPendingFile.delete();
   1583                     mPendingInits.remove(transportName);
   1584                 }
   1585                 return; // done; don't fall through to the error case
   1586             }
   1587         } catch (RemoteException e) {
   1588             // transport threw when asked its name; fall through to the lookup-failed case
   1589         }
   1590 
   1591         // The named transport doesn't exist or threw.  This operation is
   1592         // important, so we record the need for a an init and post a message
   1593         // to retry the init later.
   1594         if (isPending) {
   1595             mPendingInits.add(transportName);
   1596             mBackupHandler.sendMessageDelayed(
   1597                     mBackupHandler.obtainMessage(MSG_RETRY_INIT,
   1598                             (isPending ? 1 : 0),
   1599                             0,
   1600                             transportName),
   1601                     TRANSPORT_RETRY_INTERVAL);
   1602         }
   1603     }
   1604 
   1605     // Reset all of our bookkeeping, in response to having been told that
   1606     // the backend data has been wiped [due to idle expiry, for example],
   1607     // so we must re-upload all saved settings.
   1608     void resetBackupState(File stateFileDir) {
   1609         synchronized (mQueueLock) {
   1610             // Wipe the "what we've ever backed up" tracking
   1611             mEverStoredApps.clear();
   1612             mEverStored.delete();
   1613 
   1614             mCurrentToken = 0;
   1615             writeRestoreTokens();
   1616 
   1617             // Remove all the state files
   1618             for (File sf : stateFileDir.listFiles()) {
   1619                 // ... but don't touch the needs-init sentinel
   1620                 if (!sf.getName().equals(INIT_SENTINEL_FILE_NAME)) {
   1621                     sf.delete();
   1622                 }
   1623             }
   1624         }
   1625 
   1626         // Enqueue a new backup of every participant
   1627         synchronized (mBackupParticipants) {
   1628             final int N = mBackupParticipants.size();
   1629             for (int i=0; i<N; i++) {
   1630                 HashSet<String> participants = mBackupParticipants.valueAt(i);
   1631                 if (participants != null) {
   1632                     for (String packageName : participants) {
   1633                         dataChangedImpl(packageName);
   1634                     }
   1635                 }
   1636             }
   1637         }
   1638     }
   1639 
   1640     // Add a transport to our set of available backends.  If 'transport' is null, this
   1641     // is an unregistration, and the transport's entry is removed from our bookkeeping.
   1642     private void registerTransport(String name, String component, IBackupTransport transport) {
   1643         synchronized (mTransports) {
   1644             if (DEBUG) Slog.v(TAG, "Registering transport "
   1645                     + component + "::" + name + " = " + transport);
   1646             if (transport != null) {
   1647                 mTransports.put(name, transport);
   1648                 mTransportNames.put(component, name);
   1649             } else {
   1650                 mTransports.remove(mTransportNames.get(component));
   1651                 mTransportNames.remove(component);
   1652                 // Nothing further to do in the unregistration case
   1653                 return;
   1654             }
   1655         }
   1656 
   1657         // If the init sentinel file exists, we need to be sure to perform the init
   1658         // as soon as practical.  We also create the state directory at registration
   1659         // time to ensure it's present from the outset.
   1660         try {
   1661             String transportName = transport.transportDirName();
   1662             File stateDir = new File(mBaseStateDir, transportName);
   1663             stateDir.mkdirs();
   1664 
   1665             File initSentinel = new File(stateDir, INIT_SENTINEL_FILE_NAME);
   1666             if (initSentinel.exists()) {
   1667                 synchronized (mQueueLock) {
   1668                     mPendingInits.add(transportName);
   1669 
   1670                     // TODO: pick a better starting time than now + 1 minute
   1671                     long delay = 1000 * 60; // one minute, in milliseconds
   1672                     mAlarmManager.set(AlarmManager.RTC_WAKEUP,
   1673                             System.currentTimeMillis() + delay, mRunInitIntent);
   1674                 }
   1675             }
   1676         } catch (RemoteException e) {
   1677             // the transport threw when asked its file naming prefs; declare it invalid
   1678             Slog.e(TAG, "Unable to register transport as " + name);
   1679             mTransportNames.remove(component);
   1680             mTransports.remove(name);
   1681         }
   1682     }
   1683 
   1684     // ----- Track installation/removal of packages -----
   1685     BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
   1686         public void onReceive(Context context, Intent intent) {
   1687             if (DEBUG) Slog.d(TAG, "Received broadcast " + intent);
   1688 
   1689             String action = intent.getAction();
   1690             boolean replacing = false;
   1691             boolean added = false;
   1692             boolean changed = false;
   1693             Bundle extras = intent.getExtras();
   1694             String pkgList[] = null;
   1695             if (Intent.ACTION_PACKAGE_ADDED.equals(action) ||
   1696                     Intent.ACTION_PACKAGE_REMOVED.equals(action) ||
   1697                     Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
   1698                 Uri uri = intent.getData();
   1699                 if (uri == null) {
   1700                     return;
   1701                 }
   1702                 String pkgName = uri.getSchemeSpecificPart();
   1703                 if (pkgName != null) {
   1704                     pkgList = new String[] { pkgName };
   1705                 }
   1706                 changed = Intent.ACTION_PACKAGE_CHANGED.equals(action);
   1707 
   1708                 // At package-changed we only care about looking at new transport states
   1709                 if (changed) {
   1710                     try {
   1711                         if (MORE_DEBUG) {
   1712                             Slog.i(TAG, "Package " + pkgName + " changed; rechecking");
   1713                         }
   1714                         // unbind existing possibly-stale connections to that package's transports
   1715                         synchronized (mTransports) {
   1716                             TransportConnection conn = mTransportConnections.get(pkgName);
   1717                             if (conn != null) {
   1718                                 final ServiceInfo svc = conn.mTransport;
   1719                                 ComponentName svcName =
   1720                                         new ComponentName(svc.packageName, svc.name);
   1721                                 String flatName = svcName.flattenToShortString();
   1722                                 Slog.i(TAG, "Unbinding " + svcName);
   1723 
   1724                                 mContext.unbindService(conn);
   1725                                 mTransportConnections.remove(pkgName);
   1726                                 mTransports.remove(mTransportNames.get(flatName));
   1727                                 mTransportNames.remove(flatName);
   1728                             }
   1729                         }
   1730                         // and then (re)bind as appropriate
   1731                         PackageInfo app = mPackageManager.getPackageInfo(pkgName, 0);
   1732                         checkForTransportAndBind(app);
   1733                     } catch (NameNotFoundException e) {
   1734                         // Nope, can't find it - just ignore
   1735                         if (MORE_DEBUG) {
   1736                             Slog.w(TAG, "Can't find changed package " + pkgName);
   1737                         }
   1738                     }
   1739                     return; // nothing more to do in the PACKAGE_CHANGED case
   1740                 }
   1741 
   1742                 added = Intent.ACTION_PACKAGE_ADDED.equals(action);
   1743                 replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false);
   1744             } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
   1745                 added = true;
   1746                 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
   1747             } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
   1748                 added = false;
   1749                 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
   1750             }
   1751 
   1752             if (pkgList == null || pkgList.length == 0) {
   1753                 return;
   1754             }
   1755 
   1756             final int uid = extras.getInt(Intent.EXTRA_UID);
   1757             if (added) {
   1758                 synchronized (mBackupParticipants) {
   1759                     if (replacing) {
   1760                         // This is the package-replaced case; we just remove the entry
   1761                         // under the old uid and fall through to re-add.
   1762                         removePackageParticipantsLocked(pkgList, uid);
   1763                     }
   1764                     addPackageParticipantsLocked(pkgList);
   1765                 }
   1766                 // If they're full-backup candidates, add them there instead
   1767                 for (String packageName : pkgList) {
   1768                     try {
   1769                         PackageInfo app = mPackageManager.getPackageInfo(packageName, 0);
   1770                         long now = System.currentTimeMillis();
   1771                         if (appGetsFullBackup(app)) {
   1772                             enqueueFullBackup(packageName, now);
   1773                             scheduleNextFullBackupJob();
   1774                         }
   1775 
   1776                         // Transport maintenance: rebind to known existing transports that have
   1777                         // just been updated; and bind to any newly-installed transport services.
   1778                         synchronized (mTransports) {
   1779                             final TransportConnection conn = mTransportConnections.get(packageName);
   1780                             if (conn != null) {
   1781                                 if (MORE_DEBUG) {
   1782                                     Slog.i(TAG, "Transport package changed; rebinding");
   1783                                 }
   1784                                 bindTransport(conn.mTransport);
   1785                             } else {
   1786                                 checkForTransportAndBind(app);
   1787                             }
   1788                         }
   1789 
   1790                     } catch (NameNotFoundException e) {
   1791                         // doesn't really exist; ignore it
   1792                         if (DEBUG) {
   1793                             Slog.i(TAG, "Can't resolve new app " + packageName);
   1794                         }
   1795                     }
   1796                 }
   1797 
   1798             } else {
   1799                 if (replacing) {
   1800                     // The package is being updated.  We'll receive a PACKAGE_ADDED shortly.
   1801                 } else {
   1802                     synchronized (mBackupParticipants) {
   1803                         removePackageParticipantsLocked(pkgList, uid);
   1804                     }
   1805                 }
   1806             }
   1807         }
   1808     };
   1809 
   1810     // ----- Track connection to transports service -----
   1811     class TransportConnection implements ServiceConnection {
   1812         ServiceInfo mTransport;
   1813 
   1814         public TransportConnection(ServiceInfo transport) {
   1815             mTransport = transport;
   1816         }
   1817 
   1818         @Override
   1819         public void onServiceConnected(ComponentName component, IBinder service) {
   1820             if (DEBUG) Slog.v(TAG, "Connected to transport " + component);
   1821             final String name = component.flattenToShortString();
   1822             try {
   1823                 IBackupTransport transport = IBackupTransport.Stub.asInterface(service);
   1824                 registerTransport(transport.name(), name, transport);
   1825                 EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE, name, 1);
   1826             } catch (RemoteException e) {
   1827                 Slog.e(TAG, "Unable to register transport " + component);
   1828                 EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE, name, 0);
   1829             }
   1830         }
   1831 
   1832         @Override
   1833         public void onServiceDisconnected(ComponentName component) {
   1834             if (DEBUG) Slog.v(TAG, "Disconnected from transport " + component);
   1835             final String name = component.flattenToShortString();
   1836             EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE, name, 0);
   1837             registerTransport(null, name, null);
   1838         }
   1839     };
   1840 
   1841     // Check whether the given package hosts a transport, and bind if so
   1842     void checkForTransportAndBind(PackageInfo pkgInfo) {
   1843         Intent intent = new Intent(mTransportServiceIntent)
   1844                 .setPackage(pkgInfo.packageName);
   1845         List<ResolveInfo> hosts = mPackageManager.queryIntentServicesAsUser(
   1846                 intent, 0, UserHandle.USER_OWNER);
   1847         final int N = hosts.size();
   1848         for (int i = 0; i < N; i++) {
   1849             final ServiceInfo info = hosts.get(i).serviceInfo;
   1850             tryBindTransport(info);
   1851         }
   1852     }
   1853 
   1854     // Verify that the service exists and is hosted by a privileged app, then proceed to bind
   1855     boolean tryBindTransport(ServiceInfo info) {
   1856         try {
   1857             PackageInfo packInfo = mPackageManager.getPackageInfo(info.packageName, 0);
   1858             if ((packInfo.applicationInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
   1859                 return bindTransport(info);
   1860             } else {
   1861                 Slog.w(TAG, "Transport package " + info.packageName + " not privileged");
   1862             }
   1863         } catch (NameNotFoundException e) {
   1864             Slog.w(TAG, "Problem resolving transport package " + info.packageName);
   1865         }
   1866         return false;
   1867     }
   1868 
   1869     // Actually bind; presumes that we have already validated the transport service
   1870     boolean bindTransport(ServiceInfo transport) {
   1871         ComponentName svcName = new ComponentName(transport.packageName, transport.name);
   1872         if (DEBUG) {
   1873             Slog.i(TAG, "Binding to transport host " + svcName);
   1874         }
   1875         Intent intent = new Intent(mTransportServiceIntent);
   1876         intent.setComponent(svcName);
   1877 
   1878         TransportConnection connection;
   1879         synchronized (mTransports) {
   1880             connection = mTransportConnections.get(transport.packageName);
   1881             if (null == connection) {
   1882                 connection = new TransportConnection(transport);
   1883                 mTransportConnections.put(transport.packageName, connection);
   1884             } else {
   1885                 // This is a rebind due to package upgrade.  The service won't be
   1886                 // automatically relaunched for us until we explicitly rebind, but
   1887                 // we need to unbind the now-orphaned original connection.
   1888                 mContext.unbindService(connection);
   1889             }
   1890         }
   1891         return mContext.bindServiceAsUser(intent,
   1892                 connection, Context.BIND_AUTO_CREATE,
   1893                 UserHandle.OWNER);
   1894     }
   1895 
   1896     // Add the backup agents in the given packages to our set of known backup participants.
   1897     // If 'packageNames' is null, adds all backup agents in the whole system.
   1898     void addPackageParticipantsLocked(String[] packageNames) {
   1899         // Look for apps that define the android:backupAgent attribute
   1900         List<PackageInfo> targetApps = allAgentPackages();
   1901         if (packageNames != null) {
   1902             if (MORE_DEBUG) Slog.v(TAG, "addPackageParticipantsLocked: #" + packageNames.length);
   1903             for (String packageName : packageNames) {
   1904                 addPackageParticipantsLockedInner(packageName, targetApps);
   1905             }
   1906         } else {
   1907             if (MORE_DEBUG) Slog.v(TAG, "addPackageParticipantsLocked: all");
   1908             addPackageParticipantsLockedInner(null, targetApps);
   1909         }
   1910     }
   1911 
   1912     private void addPackageParticipantsLockedInner(String packageName,
   1913             List<PackageInfo> targetPkgs) {
   1914         if (MORE_DEBUG) {
   1915             Slog.v(TAG, "Examining " + packageName + " for backup agent");
   1916         }
   1917 
   1918         for (PackageInfo pkg : targetPkgs) {
   1919             if (packageName == null || pkg.packageName.equals(packageName)) {
   1920                 int uid = pkg.applicationInfo.uid;
   1921                 HashSet<String> set = mBackupParticipants.get(uid);
   1922                 if (set == null) {
   1923                     set = new HashSet<String>();
   1924                     mBackupParticipants.put(uid, set);
   1925                 }
   1926                 set.add(pkg.packageName);
   1927                 if (MORE_DEBUG) Slog.v(TAG, "Agent found; added");
   1928 
   1929                 // Schedule a backup for it on general principles
   1930                 if (MORE_DEBUG) Slog.i(TAG, "Scheduling backup for new app " + pkg.packageName);
   1931                 dataChangedImpl(pkg.packageName);
   1932             }
   1933         }
   1934     }
   1935 
   1936     // Remove the given packages' entries from our known active set.
   1937     void removePackageParticipantsLocked(String[] packageNames, int oldUid) {
   1938         if (packageNames == null) {
   1939             Slog.w(TAG, "removePackageParticipants with null list");
   1940             return;
   1941         }
   1942 
   1943         if (MORE_DEBUG) Slog.v(TAG, "removePackageParticipantsLocked: uid=" + oldUid
   1944                 + " #" + packageNames.length);
   1945         for (String pkg : packageNames) {
   1946             // Known previous UID, so we know which package set to check
   1947             HashSet<String> set = mBackupParticipants.get(oldUid);
   1948             if (set != null && set.contains(pkg)) {
   1949                 removePackageFromSetLocked(set, pkg);
   1950                 if (set.isEmpty()) {
   1951                     if (MORE_DEBUG) Slog.v(TAG, "  last one of this uid; purging set");
   1952                     mBackupParticipants.remove(oldUid);
   1953                 }
   1954             }
   1955         }
   1956     }
   1957 
   1958     private void removePackageFromSetLocked(final HashSet<String> set,
   1959             final String packageName) {
   1960         if (set.contains(packageName)) {
   1961             // Found it.  Remove this one package from the bookkeeping, and
   1962             // if it's the last participating app under this uid we drop the
   1963             // (now-empty) set as well.
   1964             // Note that we deliberately leave it 'known' in the "ever backed up"
   1965             // bookkeeping so that its current-dataset data will be retrieved
   1966             // if the app is subsequently reinstalled
   1967             if (MORE_DEBUG) Slog.v(TAG, "  removing participant " + packageName);
   1968             set.remove(packageName);
   1969             mPendingBackups.remove(packageName);
   1970         }
   1971     }
   1972 
   1973     // Returns the set of all applications that define an android:backupAgent attribute
   1974     List<PackageInfo> allAgentPackages() {
   1975         // !!! TODO: cache this and regenerate only when necessary
   1976         int flags = PackageManager.GET_SIGNATURES;
   1977         List<PackageInfo> packages = mPackageManager.getInstalledPackages(flags);
   1978         int N = packages.size();
   1979         for (int a = N-1; a >= 0; a--) {
   1980             PackageInfo pkg = packages.get(a);
   1981             try {
   1982                 ApplicationInfo app = pkg.applicationInfo;
   1983                 if (((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0)
   1984                         || app.backupAgentName == null) {
   1985                     packages.remove(a);
   1986                 }
   1987                 else {
   1988                     // we will need the shared library path, so look that up and store it here.
   1989                     // This is used implicitly when we pass the PackageInfo object off to
   1990                     // the Activity Manager to launch the app for backup/restore purposes.
   1991                     app = mPackageManager.getApplicationInfo(pkg.packageName,
   1992                             PackageManager.GET_SHARED_LIBRARY_FILES);
   1993                     pkg.applicationInfo.sharedLibraryFiles = app.sharedLibraryFiles;
   1994                 }
   1995             } catch (NameNotFoundException e) {
   1996                 packages.remove(a);
   1997             }
   1998         }
   1999         return packages;
   2000     }
   2001 
   2002     // Called from the backup tasks: record that the given app has been successfully
   2003     // backed up at least once.  This includes both key/value and full-data backups
   2004     // through the transport.
   2005     void logBackupComplete(String packageName) {
   2006         if (packageName.equals(PACKAGE_MANAGER_SENTINEL)) return;
   2007 
   2008         synchronized (mEverStoredApps) {
   2009             if (!mEverStoredApps.add(packageName)) return;
   2010 
   2011             RandomAccessFile out = null;
   2012             try {
   2013                 out = new RandomAccessFile(mEverStored, "rws");
   2014                 out.seek(out.length());
   2015                 out.writeUTF(packageName);
   2016             } catch (IOException e) {
   2017                 Slog.e(TAG, "Can't log backup of " + packageName + " to " + mEverStored);
   2018             } finally {
   2019                 try { if (out != null) out.close(); } catch (IOException e) {}
   2020             }
   2021         }
   2022     }
   2023 
   2024     // Remove our awareness of having ever backed up the given package
   2025     void removeEverBackedUp(String packageName) {
   2026         if (DEBUG) Slog.v(TAG, "Removing backed-up knowledge of " + packageName);
   2027         if (MORE_DEBUG) Slog.v(TAG, "New set:");
   2028 
   2029         synchronized (mEverStoredApps) {
   2030             // Rewrite the file and rename to overwrite.  If we reboot in the middle,
   2031             // we'll recognize on initialization time that the package no longer
   2032             // exists and fix it up then.
   2033             File tempKnownFile = new File(mBaseStateDir, "processed.new");
   2034             RandomAccessFile known = null;
   2035             try {
   2036                 known = new RandomAccessFile(tempKnownFile, "rws");
   2037                 mEverStoredApps.remove(packageName);
   2038                 for (String s : mEverStoredApps) {
   2039                     known.writeUTF(s);
   2040                     if (MORE_DEBUG) Slog.v(TAG, "    " + s);
   2041                 }
   2042                 known.close();
   2043                 known = null;
   2044                 if (!tempKnownFile.renameTo(mEverStored)) {
   2045                     throw new IOException("Can't rename " + tempKnownFile + " to " + mEverStored);
   2046                 }
   2047             } catch (IOException e) {
   2048                 // Bad: we couldn't create the new copy.  For safety's sake we
   2049                 // abandon the whole process and remove all what's-backed-up
   2050                 // state entirely, meaning we'll force a backup pass for every
   2051                 // participant on the next boot or [re]install.
   2052                 Slog.w(TAG, "Error rewriting " + mEverStored, e);
   2053                 mEverStoredApps.clear();
   2054                 tempKnownFile.delete();
   2055                 mEverStored.delete();
   2056             } finally {
   2057                 try { if (known != null) known.close(); } catch (IOException e) {}
   2058             }
   2059         }
   2060     }
   2061 
   2062     // Persistently record the current and ancestral backup tokens as well
   2063     // as the set of packages with data [supposedly] available in the
   2064     // ancestral dataset.
   2065     void writeRestoreTokens() {
   2066         try {
   2067             RandomAccessFile af = new RandomAccessFile(mTokenFile, "rwd");
   2068 
   2069             // First, the version number of this record, for futureproofing
   2070             af.writeInt(CURRENT_ANCESTRAL_RECORD_VERSION);
   2071 
   2072             // Write the ancestral and current tokens
   2073             af.writeLong(mAncestralToken);
   2074             af.writeLong(mCurrentToken);
   2075 
   2076             // Now write the set of ancestral packages
   2077             if (mAncestralPackages == null) {
   2078                 af.writeInt(-1);
   2079             } else {
   2080                 af.writeInt(mAncestralPackages.size());
   2081                 if (DEBUG) Slog.v(TAG, "Ancestral packages:  " + mAncestralPackages.size());
   2082                 for (String pkgName : mAncestralPackages) {
   2083                     af.writeUTF(pkgName);
   2084                     if (MORE_DEBUG) Slog.v(TAG, "   " + pkgName);
   2085                 }
   2086             }
   2087             af.close();
   2088         } catch (IOException e) {
   2089             Slog.w(TAG, "Unable to write token file:", e);
   2090         }
   2091     }
   2092 
   2093     // Return the given transport
   2094     private IBackupTransport getTransport(String transportName) {
   2095         synchronized (mTransports) {
   2096             IBackupTransport transport = mTransports.get(transportName);
   2097             if (transport == null) {
   2098                 Slog.w(TAG, "Requested unavailable transport: " + transportName);
   2099             }
   2100             return transport;
   2101         }
   2102     }
   2103 
   2104     // fire off a backup agent, blocking until it attaches or times out
   2105     IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode) {
   2106         IBackupAgent agent = null;
   2107         synchronized(mAgentConnectLock) {
   2108             mConnecting = true;
   2109             mConnectedAgent = null;
   2110             try {
   2111                 if (mActivityManager.bindBackupAgent(app, mode)) {
   2112                     Slog.d(TAG, "awaiting agent for " + app);
   2113 
   2114                     // success; wait for the agent to arrive
   2115                     // only wait 10 seconds for the bind to happen
   2116                     long timeoutMark = System.currentTimeMillis() + TIMEOUT_INTERVAL;
   2117                     while (mConnecting && mConnectedAgent == null
   2118                             && (System.currentTimeMillis() < timeoutMark)) {
   2119                         try {
   2120                             mAgentConnectLock.wait(5000);
   2121                         } catch (InterruptedException e) {
   2122                             // just bail
   2123                             if (DEBUG) Slog.w(TAG, "Interrupted: " + e);
   2124                             mActivityManager.clearPendingBackup();
   2125                             return null;
   2126                         }
   2127                     }
   2128 
   2129                     // if we timed out with no connect, abort and move on
   2130                     if (mConnecting == true) {
   2131                         Slog.w(TAG, "Timeout waiting for agent " + app);
   2132                         mActivityManager.clearPendingBackup();
   2133                         return null;
   2134                     }
   2135                     if (DEBUG) Slog.i(TAG, "got agent " + mConnectedAgent);
   2136                     agent = mConnectedAgent;
   2137                 }
   2138             } catch (RemoteException e) {
   2139                 // can't happen - ActivityManager is local
   2140             }
   2141         }
   2142         return agent;
   2143     }
   2144 
   2145     // clear an application's data, blocking until the operation completes or times out
   2146     void clearApplicationDataSynchronous(String packageName) {
   2147         // Don't wipe packages marked allowClearUserData=false
   2148         try {
   2149             PackageInfo info = mPackageManager.getPackageInfo(packageName, 0);
   2150             if ((info.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA) == 0) {
   2151                 if (MORE_DEBUG) Slog.i(TAG, "allowClearUserData=false so not wiping "
   2152                         + packageName);
   2153                 return;
   2154             }
   2155         } catch (NameNotFoundException e) {
   2156             Slog.w(TAG, "Tried to clear data for " + packageName + " but not found");
   2157             return;
   2158         }
   2159 
   2160         ClearDataObserver observer = new ClearDataObserver();
   2161 
   2162         synchronized(mClearDataLock) {
   2163             mClearingData = true;
   2164             try {
   2165                 mActivityManager.clearApplicationUserData(packageName, observer, 0);
   2166             } catch (RemoteException e) {
   2167                 // can't happen because the activity manager is in this process
   2168             }
   2169 
   2170             // only wait 10 seconds for the clear data to happen
   2171             long timeoutMark = System.currentTimeMillis() + TIMEOUT_INTERVAL;
   2172             while (mClearingData && (System.currentTimeMillis() < timeoutMark)) {
   2173                 try {
   2174                     mClearDataLock.wait(5000);
   2175                 } catch (InterruptedException e) {
   2176                     // won't happen, but still.
   2177                     mClearingData = false;
   2178                 }
   2179             }
   2180         }
   2181     }
   2182 
   2183     class ClearDataObserver extends IPackageDataObserver.Stub {
   2184         public void onRemoveCompleted(String packageName, boolean succeeded) {
   2185             synchronized(mClearDataLock) {
   2186                 mClearingData = false;
   2187                 mClearDataLock.notifyAll();
   2188             }
   2189         }
   2190     }
   2191 
   2192     // Get the restore-set token for the best-available restore set for this package:
   2193     // the active set if possible, else the ancestral one.  Returns zero if none available.
   2194     long getAvailableRestoreToken(String packageName) {
   2195         long token = mAncestralToken;
   2196         synchronized (mQueueLock) {
   2197             if (mEverStoredApps.contains(packageName)) {
   2198                 token = mCurrentToken;
   2199             }
   2200         }
   2201         return token;
   2202     }
   2203 
   2204     // -----
   2205     // Interface and methods used by the asynchronous-with-timeout backup/restore operations
   2206 
   2207     interface BackupRestoreTask {
   2208         // Execute one tick of whatever state machine the task implements
   2209         void execute();
   2210 
   2211         // An operation that wanted a callback has completed
   2212         void operationComplete();
   2213 
   2214         // An operation that wanted a callback has timed out
   2215         void handleTimeout();
   2216     }
   2217 
   2218     void prepareOperationTimeout(int token, long interval, BackupRestoreTask callback) {
   2219         if (MORE_DEBUG) Slog.v(TAG, "starting timeout: token=" + Integer.toHexString(token)
   2220                 + " interval=" + interval);
   2221         synchronized (mCurrentOpLock) {
   2222             mCurrentOperations.put(token, new Operation(OP_PENDING, callback));
   2223 
   2224             Message msg = mBackupHandler.obtainMessage(MSG_TIMEOUT, token, 0, callback);
   2225             mBackupHandler.sendMessageDelayed(msg, interval);
   2226         }
   2227     }
   2228 
   2229     // synchronous waiter case
   2230     boolean waitUntilOperationComplete(int token) {
   2231         if (MORE_DEBUG) Slog.i(TAG, "Blocking until operation complete for "
   2232                 + Integer.toHexString(token));
   2233         int finalState = OP_PENDING;
   2234         Operation op = null;
   2235         synchronized (mCurrentOpLock) {
   2236             while (true) {
   2237                 op = mCurrentOperations.get(token);
   2238                 if (op == null) {
   2239                     // mysterious disappearance: treat as success with no callback
   2240                     break;
   2241                 } else {
   2242                     if (op.state == OP_PENDING) {
   2243                         try {
   2244                             mCurrentOpLock.wait();
   2245                         } catch (InterruptedException e) {}
   2246                         // When the wait is notified we loop around and recheck the current state
   2247                     } else {
   2248                         // No longer pending; we're done
   2249                         finalState = op.state;
   2250                         break;
   2251                     }
   2252                 }
   2253             }
   2254         }
   2255 
   2256         mBackupHandler.removeMessages(MSG_TIMEOUT);
   2257         if (MORE_DEBUG) Slog.v(TAG, "operation " + Integer.toHexString(token)
   2258                 + " complete: finalState=" + finalState);
   2259         return finalState == OP_ACKNOWLEDGED;
   2260     }
   2261 
   2262     void handleTimeout(int token, Object obj) {
   2263         // Notify any synchronous waiters
   2264         Operation op = null;
   2265         synchronized (mCurrentOpLock) {
   2266             op = mCurrentOperations.get(token);
   2267             if (MORE_DEBUG) {
   2268                 if (op == null) Slog.w(TAG, "Timeout of token " + Integer.toHexString(token)
   2269                         + " but no op found");
   2270             }
   2271             int state = (op != null) ? op.state : OP_TIMEOUT;
   2272             if (state == OP_PENDING) {
   2273                 if (DEBUG) Slog.v(TAG, "TIMEOUT: token=" + Integer.toHexString(token));
   2274                 op.state = OP_TIMEOUT;
   2275                 mCurrentOperations.put(token, op);
   2276             }
   2277             mCurrentOpLock.notifyAll();
   2278         }
   2279 
   2280         // If there's a TimeoutHandler for this event, call it
   2281         if (op != null && op.callback != null) {
   2282             op.callback.handleTimeout();
   2283         }
   2284     }
   2285 
   2286     // ----- Back up a set of applications via a worker thread -----
   2287 
   2288     enum BackupState {
   2289         INITIAL,
   2290         RUNNING_QUEUE,
   2291         FINAL
   2292     }
   2293 
   2294     class PerformBackupTask implements BackupRestoreTask {
   2295         private static final String TAG = "PerformBackupTask";
   2296 
   2297         IBackupTransport mTransport;
   2298         ArrayList<BackupRequest> mQueue;
   2299         ArrayList<BackupRequest> mOriginalQueue;
   2300         File mStateDir;
   2301         File mJournal;
   2302         BackupState mCurrentState;
   2303 
   2304         // carried information about the current in-flight operation
   2305         IBackupAgent mAgentBinder;
   2306         PackageInfo mCurrentPackage;
   2307         File mSavedStateName;
   2308         File mBackupDataName;
   2309         File mNewStateName;
   2310         ParcelFileDescriptor mSavedState;
   2311         ParcelFileDescriptor mBackupData;
   2312         ParcelFileDescriptor mNewState;
   2313         int mStatus;
   2314         boolean mFinished;
   2315 
   2316         public PerformBackupTask(IBackupTransport transport, String dirName,
   2317                 ArrayList<BackupRequest> queue, File journal) {
   2318             mTransport = transport;
   2319             mOriginalQueue = queue;
   2320             mJournal = journal;
   2321 
   2322             mStateDir = new File(mBaseStateDir, dirName);
   2323 
   2324             mCurrentState = BackupState.INITIAL;
   2325             mFinished = false;
   2326 
   2327             addBackupTrace("STATE => INITIAL");
   2328         }
   2329 
   2330         // Main entry point: perform one chunk of work, updating the state as appropriate
   2331         // and reposting the next chunk to the primary backup handler thread.
   2332         @Override
   2333         public void execute() {
   2334             switch (mCurrentState) {
   2335                 case INITIAL:
   2336                     beginBackup();
   2337                     break;
   2338 
   2339                 case RUNNING_QUEUE:
   2340                     invokeNextAgent();
   2341                     break;
   2342 
   2343                 case FINAL:
   2344                     if (!mFinished) finalizeBackup();
   2345                     else {
   2346                         Slog.e(TAG, "Duplicate finish");
   2347                     }
   2348                     mFinished = true;
   2349                     break;
   2350             }
   2351         }
   2352 
   2353         // We're starting a backup pass.  Initialize the transport and send
   2354         // the PM metadata blob if we haven't already.
   2355         void beginBackup() {
   2356             if (DEBUG_BACKUP_TRACE) {
   2357                 clearBackupTrace();
   2358                 StringBuilder b = new StringBuilder(256);
   2359                 b.append("beginBackup: [");
   2360                 for (BackupRequest req : mOriginalQueue) {
   2361                     b.append(' ');
   2362                     b.append(req.packageName);
   2363                 }
   2364                 b.append(" ]");
   2365                 addBackupTrace(b.toString());
   2366             }
   2367 
   2368             mAgentBinder = null;
   2369             mStatus = BackupTransport.TRANSPORT_OK;
   2370 
   2371             // Sanity check: if the queue is empty we have no work to do.
   2372             if (mOriginalQueue.isEmpty()) {
   2373                 Slog.w(TAG, "Backup begun with an empty queue - nothing to do.");
   2374                 addBackupTrace("queue empty at begin");
   2375                 executeNextState(BackupState.FINAL);
   2376                 return;
   2377             }
   2378 
   2379             // We need to retain the original queue contents in case of transport
   2380             // failure, but we want a working copy that we can manipulate along
   2381             // the way.
   2382             mQueue = (ArrayList<BackupRequest>) mOriginalQueue.clone();
   2383 
   2384             if (DEBUG) Slog.v(TAG, "Beginning backup of " + mQueue.size() + " targets");
   2385 
   2386             File pmState = new File(mStateDir, PACKAGE_MANAGER_SENTINEL);
   2387             try {
   2388                 final String transportName = mTransport.transportDirName();
   2389                 EventLog.writeEvent(EventLogTags.BACKUP_START, transportName);
   2390 
   2391                 // If we haven't stored package manager metadata yet, we must init the transport.
   2392                 if (mStatus == BackupTransport.TRANSPORT_OK && pmState.length() <= 0) {
   2393                     Slog.i(TAG, "Initializing (wiping) backup state and transport storage");
   2394                     addBackupTrace("initializing transport " + transportName);
   2395                     resetBackupState(mStateDir);  // Just to make sure.
   2396                     mStatus = mTransport.initializeDevice();
   2397 
   2398                     addBackupTrace("transport.initializeDevice() == " + mStatus);
   2399                     if (mStatus == BackupTransport.TRANSPORT_OK) {
   2400                         EventLog.writeEvent(EventLogTags.BACKUP_INITIALIZE);
   2401                     } else {
   2402                         EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, "(initialize)");
   2403                         Slog.e(TAG, "Transport error in initializeDevice()");
   2404                     }
   2405                 }
   2406 
   2407                 // The package manager doesn't have a proper <application> etc, but since
   2408                 // it's running here in the system process we can just set up its agent
   2409                 // directly and use a synthetic BackupRequest.  We always run this pass
   2410                 // because it's cheap and this way we guarantee that we don't get out of
   2411                 // step even if we're selecting among various transports at run time.
   2412                 if (mStatus == BackupTransport.TRANSPORT_OK) {
   2413                     PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
   2414                             mPackageManager);
   2415                     mStatus = invokeAgentForBackup(PACKAGE_MANAGER_SENTINEL,
   2416                             IBackupAgent.Stub.asInterface(pmAgent.onBind()), mTransport);
   2417                     addBackupTrace("PMBA invoke: " + mStatus);
   2418 
   2419                     // Because the PMBA is a local instance, it has already executed its
   2420                     // backup callback and returned.  Blow away the lingering (spurious)
   2421                     // pending timeout message for it.
   2422                     mBackupHandler.removeMessages(MSG_TIMEOUT);
   2423                 }
   2424 
   2425                 if (mStatus == BackupTransport.TRANSPORT_NOT_INITIALIZED) {
   2426                     // The backend reports that our dataset has been wiped.  Note this in
   2427                     // the event log; the no-success code below will reset the backup
   2428                     // state as well.
   2429                     EventLog.writeEvent(EventLogTags.BACKUP_RESET, mTransport.transportDirName());
   2430                 }
   2431             } catch (Exception e) {
   2432                 Slog.e(TAG, "Error in backup thread", e);
   2433                 addBackupTrace("Exception in backup thread: " + e);
   2434                 mStatus = BackupTransport.TRANSPORT_ERROR;
   2435             } finally {
   2436                 // If we've succeeded so far, invokeAgentForBackup() will have run the PM
   2437                 // metadata and its completion/timeout callback will continue the state
   2438                 // machine chain.  If it failed that won't happen; we handle that now.
   2439                 addBackupTrace("exiting prelim: " + mStatus);
   2440                 if (mStatus != BackupTransport.TRANSPORT_OK) {
   2441                     // if things went wrong at this point, we need to
   2442                     // restage everything and try again later.
   2443                     resetBackupState(mStateDir);  // Just to make sure.
   2444                     executeNextState(BackupState.FINAL);
   2445                 }
   2446             }
   2447         }
   2448 
   2449         // Transport has been initialized and the PM metadata submitted successfully
   2450         // if that was warranted.  Now we process the single next thing in the queue.
   2451         void invokeNextAgent() {
   2452             mStatus = BackupTransport.TRANSPORT_OK;
   2453             addBackupTrace("invoke q=" + mQueue.size());
   2454 
   2455             // Sanity check that we have work to do.  If not, skip to the end where
   2456             // we reestablish the wakelock invariants etc.
   2457             if (mQueue.isEmpty()) {
   2458                 if (DEBUG) Slog.i(TAG, "queue now empty");
   2459                 executeNextState(BackupState.FINAL);
   2460                 return;
   2461             }
   2462 
   2463             // pop the entry we're going to process on this step
   2464             BackupRequest request = mQueue.get(0);
   2465             mQueue.remove(0);
   2466 
   2467             Slog.d(TAG, "starting agent for backup of " + request);
   2468             addBackupTrace("launch agent for " + request.packageName);
   2469 
   2470             // Verify that the requested app exists; it might be something that
   2471             // requested a backup but was then uninstalled.  The request was
   2472             // journalled and rather than tamper with the journal it's safer
   2473             // to sanity-check here.  This also gives us the classname of the
   2474             // package's backup agent.
   2475             try {
   2476                 mCurrentPackage = mPackageManager.getPackageInfo(request.packageName,
   2477                         PackageManager.GET_SIGNATURES);
   2478                 if (mCurrentPackage.applicationInfo.backupAgentName == null) {
   2479                     // The manifest has changed but we had a stale backup request pending.
   2480                     // This won't happen again because the app won't be requesting further
   2481                     // backups.
   2482                     Slog.i(TAG, "Package " + request.packageName
   2483                             + " no longer supports backup; skipping");
   2484                     addBackupTrace("skipping - no agent, completion is noop");
   2485                     executeNextState(BackupState.RUNNING_QUEUE);
   2486                     return;
   2487                 }
   2488 
   2489                 if ((mCurrentPackage.applicationInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0) {
   2490                     // The app has been force-stopped or cleared or just installed,
   2491                     // and not yet launched out of that state, so just as it won't
   2492                     // receive broadcasts, we won't run it for backup.
   2493                     addBackupTrace("skipping - stopped");
   2494                     executeNextState(BackupState.RUNNING_QUEUE);
   2495                     return;
   2496                 }
   2497 
   2498                 IBackupAgent agent = null;
   2499                 try {
   2500                     mWakelock.setWorkSource(new WorkSource(mCurrentPackage.applicationInfo.uid));
   2501                     agent = bindToAgentSynchronous(mCurrentPackage.applicationInfo,
   2502                             IApplicationThread.BACKUP_MODE_INCREMENTAL);
   2503                     addBackupTrace("agent bound; a? = " + (agent != null));
   2504                     if (agent != null) {
   2505                         mAgentBinder = agent;
   2506                         mStatus = invokeAgentForBackup(request.packageName, agent, mTransport);
   2507                         // at this point we'll either get a completion callback from the
   2508                         // agent, or a timeout message on the main handler.  either way, we're
   2509                         // done here as long as we're successful so far.
   2510                     } else {
   2511                         // Timeout waiting for the agent
   2512                         mStatus = BackupTransport.AGENT_ERROR;
   2513                     }
   2514                 } catch (SecurityException ex) {
   2515                     // Try for the next one.
   2516                     Slog.d(TAG, "error in bind/backup", ex);
   2517                     mStatus = BackupTransport.AGENT_ERROR;
   2518                             addBackupTrace("agent SE");
   2519                 }
   2520             } catch (NameNotFoundException e) {
   2521                 Slog.d(TAG, "Package does not exist; skipping");
   2522                 addBackupTrace("no such package");
   2523                 mStatus = BackupTransport.AGENT_UNKNOWN;
   2524             } finally {
   2525                 mWakelock.setWorkSource(null);
   2526 
   2527                 // If there was an agent error, no timeout/completion handling will occur.
   2528                 // That means we need to direct to the next state ourselves.
   2529                 if (mStatus != BackupTransport.TRANSPORT_OK) {
   2530                     BackupState nextState = BackupState.RUNNING_QUEUE;
   2531                     mAgentBinder = null;
   2532 
   2533                     // An agent-level failure means we reenqueue this one agent for
   2534                     // a later retry, but otherwise proceed normally.
   2535                     if (mStatus == BackupTransport.AGENT_ERROR) {
   2536                         if (MORE_DEBUG) Slog.i(TAG, "Agent failure for " + request.packageName
   2537                                 + " - restaging");
   2538                         dataChangedImpl(request.packageName);
   2539                         mStatus = BackupTransport.TRANSPORT_OK;
   2540                         if (mQueue.isEmpty()) nextState = BackupState.FINAL;
   2541                     } else if (mStatus == BackupTransport.AGENT_UNKNOWN) {
   2542                         // Failed lookup of the app, so we couldn't bring up an agent, but
   2543                         // we're otherwise fine.  Just drop it and go on to the next as usual.
   2544                         mStatus = BackupTransport.TRANSPORT_OK;
   2545                     } else {
   2546                         // Transport-level failure means we reenqueue everything
   2547                         revertAndEndBackup();
   2548                         nextState = BackupState.FINAL;
   2549                     }
   2550 
   2551                     executeNextState(nextState);
   2552                 } else {
   2553                     // success case
   2554                     addBackupTrace("expecting completion/timeout callback");
   2555                 }
   2556             }
   2557         }
   2558 
   2559         void finalizeBackup() {
   2560             addBackupTrace("finishing");
   2561 
   2562             // Either backup was successful, in which case we of course do not need
   2563             // this pass's journal any more; or it failed, in which case we just
   2564             // re-enqueued all of these packages in the current active journal.
   2565             // Either way, we no longer need this pass's journal.
   2566             if (mJournal != null && !mJournal.delete()) {
   2567                 Slog.e(TAG, "Unable to remove backup journal file " + mJournal);
   2568             }
   2569 
   2570             // If everything actually went through and this is the first time we've
   2571             // done a backup, we can now record what the current backup dataset token
   2572             // is.
   2573             if ((mCurrentToken == 0) && (mStatus == BackupTransport.TRANSPORT_OK)) {
   2574                 addBackupTrace("success; recording token");
   2575                 try {
   2576                     mCurrentToken = mTransport.getCurrentRestoreSet();
   2577                     writeRestoreTokens();
   2578                 } catch (RemoteException e) {
   2579                     // nothing for it at this point, unfortunately, but this will be
   2580                     // recorded the next time we fully succeed.
   2581                     addBackupTrace("transport threw returning token");
   2582                 }
   2583             }
   2584 
   2585             // Set up the next backup pass - at this point we can set mBackupRunning
   2586             // to false to allow another pass to fire, because we're done with the
   2587             // state machine sequence and the wakelock is refcounted.
   2588             synchronized (mQueueLock) {
   2589                 mBackupRunning = false;
   2590                 if (mStatus == BackupTransport.TRANSPORT_NOT_INITIALIZED) {
   2591                     // Make sure we back up everything and perform the one-time init
   2592                     clearMetadata();
   2593                     if (DEBUG) Slog.d(TAG, "Server requires init; rerunning");
   2594                     addBackupTrace("init required; rerunning");
   2595                     backupNow();
   2596                 }
   2597             }
   2598 
   2599             // Only once we're entirely finished do we release the wakelock
   2600             clearBackupTrace();
   2601             Slog.i(BackupManagerService.TAG, "Backup pass finished.");
   2602             mWakelock.release();
   2603         }
   2604 
   2605         // Remove the PM metadata state. This will generate an init on the next pass.
   2606         void clearMetadata() {
   2607             final File pmState = new File(mStateDir, PACKAGE_MANAGER_SENTINEL);
   2608             if (pmState.exists()) pmState.delete();
   2609         }
   2610 
   2611         // Invoke an agent's doBackup() and start a timeout message spinning on the main
   2612         // handler in case it doesn't get back to us.
   2613         int invokeAgentForBackup(String packageName, IBackupAgent agent,
   2614                 IBackupTransport transport) {
   2615             if (DEBUG) Slog.d(TAG, "invokeAgentForBackup on " + packageName);
   2616             addBackupTrace("invoking " + packageName);
   2617 
   2618             mSavedStateName = new File(mStateDir, packageName);
   2619             mBackupDataName = new File(mDataDir, packageName + ".data");
   2620             mNewStateName = new File(mStateDir, packageName + ".new");
   2621             if (MORE_DEBUG) Slog.d(TAG, "data file: " + mBackupDataName);
   2622 
   2623             mSavedState = null;
   2624             mBackupData = null;
   2625             mNewState = null;
   2626 
   2627             final int token = generateToken();
   2628             try {
   2629                 // Look up the package info & signatures.  This is first so that if it
   2630                 // throws an exception, there's no file setup yet that would need to
   2631                 // be unraveled.
   2632                 if (packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
   2633                     // The metadata 'package' is synthetic; construct one and make
   2634                     // sure our global state is pointed at it
   2635                     mCurrentPackage = new PackageInfo();
   2636                     mCurrentPackage.packageName = packageName;
   2637                 }
   2638 
   2639                 // In a full backup, we pass a null ParcelFileDescriptor as
   2640                 // the saved-state "file". This is by definition an incremental,
   2641                 // so we build a saved state file to pass.
   2642                 mSavedState = ParcelFileDescriptor.open(mSavedStateName,
   2643                         ParcelFileDescriptor.MODE_READ_ONLY |
   2644                         ParcelFileDescriptor.MODE_CREATE);  // Make an empty file if necessary
   2645 
   2646                 mBackupData = ParcelFileDescriptor.open(mBackupDataName,
   2647                         ParcelFileDescriptor.MODE_READ_WRITE |
   2648                         ParcelFileDescriptor.MODE_CREATE |
   2649                         ParcelFileDescriptor.MODE_TRUNCATE);
   2650 
   2651                 if (!SELinux.restorecon(mBackupDataName)) {
   2652                     Slog.e(TAG, "SELinux restorecon failed on " + mBackupDataName);
   2653                 }
   2654 
   2655                 mNewState = ParcelFileDescriptor.open(mNewStateName,
   2656                         ParcelFileDescriptor.MODE_READ_WRITE |
   2657                         ParcelFileDescriptor.MODE_CREATE |
   2658                         ParcelFileDescriptor.MODE_TRUNCATE);
   2659 
   2660                 // Initiate the target's backup pass
   2661                 addBackupTrace("setting timeout");
   2662                 prepareOperationTimeout(token, TIMEOUT_BACKUP_INTERVAL, this);
   2663                 addBackupTrace("calling agent doBackup()");
   2664                 agent.doBackup(mSavedState, mBackupData, mNewState, token, mBackupManagerBinder);
   2665             } catch (Exception e) {
   2666                 Slog.e(TAG, "Error invoking for backup on " + packageName);
   2667                 addBackupTrace("exception: " + e);
   2668                 EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName,
   2669                         e.toString());
   2670                 agentErrorCleanup();
   2671                 return BackupTransport.AGENT_ERROR;
   2672             }
   2673 
   2674             // At this point the agent is off and running.  The next thing to happen will
   2675             // either be a callback from the agent, at which point we'll process its data
   2676             // for transport, or a timeout.  Either way the next phase will happen in
   2677             // response to the TimeoutHandler interface callbacks.
   2678             addBackupTrace("invoke success");
   2679             return BackupTransport.TRANSPORT_OK;
   2680         }
   2681 
   2682         public void failAgent(IBackupAgent agent, String message) {
   2683             try {
   2684                 agent.fail(message);
   2685             } catch (Exception e) {
   2686                 Slog.w(TAG, "Error conveying failure to " + mCurrentPackage.packageName);
   2687             }
   2688         }
   2689 
   2690         @Override
   2691         public void operationComplete() {
   2692             // Okay, the agent successfully reported back to us!
   2693             final String pkgName = mCurrentPackage.packageName;
   2694             final long filepos = mBackupDataName.length();
   2695             FileDescriptor fd = mBackupData.getFileDescriptor();
   2696             try {
   2697                 // If it's a 3rd party app, see whether they wrote any protected keys
   2698                 // and complain mightily if they are attempting shenanigans.
   2699                 if (mCurrentPackage.applicationInfo != null &&
   2700                         (mCurrentPackage.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
   2701                     ParcelFileDescriptor readFd = ParcelFileDescriptor.open(mBackupDataName,
   2702                             ParcelFileDescriptor.MODE_READ_ONLY);
   2703                     BackupDataInput in = new BackupDataInput(readFd.getFileDescriptor());
   2704                     try {
   2705                         while (in.readNextHeader()) {
   2706                             final String key = in.getKey();
   2707                             if (key != null && key.charAt(0) >= 0xff00) {
   2708                                 // Not okay: crash them and bail.
   2709                                 failAgent(mAgentBinder, "Illegal backup key: " + key);
   2710                                 addBackupTrace("illegal key " + key + " from " + pkgName);
   2711                                 EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, pkgName,
   2712                                         "bad key");
   2713                                 mBackupHandler.removeMessages(MSG_TIMEOUT);
   2714                                 agentErrorCleanup();
   2715                                 // agentErrorCleanup() implicitly executes next state properly
   2716                                 return;
   2717                             }
   2718                             in.skipEntityData();
   2719                         }
   2720                     } finally {
   2721                         if (readFd != null) {
   2722                             readFd.close();
   2723                         }
   2724                     }
   2725                 }
   2726 
   2727                 // Piggyback the widget state payload, if any
   2728                 BackupDataOutput out = new BackupDataOutput(fd);
   2729                 byte[] widgetState = AppWidgetBackupBridge.getWidgetState(pkgName,
   2730                         UserHandle.USER_OWNER);
   2731                 if (widgetState != null) {
   2732                     out.writeEntityHeader(KEY_WIDGET_STATE, widgetState.length);
   2733                     out.writeEntityData(widgetState, widgetState.length);
   2734                 } else {
   2735                     // No widget state for this app, but push a 'delete' operation for it
   2736                     // in case they're trying to play games with the payload.
   2737                     out.writeEntityHeader(KEY_WIDGET_STATE, -1);
   2738                 }
   2739             } catch (IOException e) {
   2740                 // Hard disk error; recovery/failure policy TBD.  For now roll back,
   2741                 // but we may want to consider this a transport-level failure (i.e.
   2742                 // we're in such a bad state that we can't contemplate doing backup
   2743                 // operations any more during this pass).
   2744                 Slog.w(TAG, "Unable to save widget state for " + pkgName);
   2745                 try {
   2746                     Os.ftruncate(fd, filepos);
   2747                 } catch (ErrnoException ee) {
   2748                     Slog.w(TAG, "Unable to roll back!");
   2749                 }
   2750             }
   2751 
   2752             // Spin the data off to the transport and proceed with the next stage.
   2753             if (MORE_DEBUG) Slog.v(TAG, "operationComplete(): sending data to transport for "
   2754                     + pkgName);
   2755             mBackupHandler.removeMessages(MSG_TIMEOUT);
   2756             clearAgentState();
   2757             addBackupTrace("operation complete");
   2758 
   2759             ParcelFileDescriptor backupData = null;
   2760             mStatus = BackupTransport.TRANSPORT_OK;
   2761             try {
   2762                 int size = (int) mBackupDataName.length();
   2763                 if (size > 0) {
   2764                     if (mStatus == BackupTransport.TRANSPORT_OK) {
   2765                         backupData = ParcelFileDescriptor.open(mBackupDataName,
   2766                                 ParcelFileDescriptor.MODE_READ_ONLY);
   2767                         addBackupTrace("sending data to transport");
   2768                         mStatus = mTransport.performBackup(mCurrentPackage, backupData);
   2769                     }
   2770 
   2771                     // TODO - We call finishBackup() for each application backed up, because
   2772                     // we need to know now whether it succeeded or failed.  Instead, we should
   2773                     // hold off on finishBackup() until the end, which implies holding off on
   2774                     // renaming *all* the output state files (see below) until that happens.
   2775 
   2776                     addBackupTrace("data delivered: " + mStatus);
   2777                     if (mStatus == BackupTransport.TRANSPORT_OK) {
   2778                         addBackupTrace("finishing op on transport");
   2779                         mStatus = mTransport.finishBackup();
   2780                         addBackupTrace("finished: " + mStatus);
   2781                     }
   2782                 } else {
   2783                     if (DEBUG) Slog.i(TAG, "no backup data written; not calling transport");
   2784                     addBackupTrace("no data to send");
   2785                 }
   2786 
   2787                 // After successful transport, delete the now-stale data
   2788                 // and juggle the files so that next time we supply the agent
   2789                 // with the new state file it just created.
   2790                 if (mStatus == BackupTransport.TRANSPORT_OK) {
   2791                     mBackupDataName.delete();
   2792                     mNewStateName.renameTo(mSavedStateName);
   2793                     EventLog.writeEvent(EventLogTags.BACKUP_PACKAGE, pkgName, size);
   2794                     logBackupComplete(pkgName);
   2795                 } else {
   2796                     EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, pkgName);
   2797                 }
   2798             } catch (Exception e) {
   2799                 Slog.e(TAG, "Transport error backing up " + pkgName, e);
   2800                 EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, pkgName);
   2801                 mStatus = BackupTransport.TRANSPORT_ERROR;
   2802             } finally {
   2803                 try { if (backupData != null) backupData.close(); } catch (IOException e) {}
   2804             }
   2805 
   2806             // If we encountered an error here it's a transport-level failure.  That
   2807             // means we need to halt everything and reschedule everything for next time.
   2808             final BackupState nextState;
   2809             if (mStatus != BackupTransport.TRANSPORT_OK) {
   2810                 revertAndEndBackup();
   2811                 nextState = BackupState.FINAL;
   2812             } else {
   2813                 // Success!  Proceed with the next app if any, otherwise we're done.
   2814                 nextState = (mQueue.isEmpty()) ? BackupState.FINAL : BackupState.RUNNING_QUEUE;
   2815             }
   2816 
   2817             executeNextState(nextState);
   2818         }
   2819 
   2820         @Override
   2821         public void handleTimeout() {
   2822             // Whoops, the current agent timed out running doBackup().  Tidy up and restage
   2823             // it for the next time we run a backup pass.
   2824             // !!! TODO: keep track of failure counts per agent, and blacklist those which
   2825             // fail repeatedly (i.e. have proved themselves to be buggy).
   2826             Slog.e(TAG, "Timeout backing up " + mCurrentPackage.packageName);
   2827             EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, mCurrentPackage.packageName,
   2828                     "timeout");
   2829             addBackupTrace("timeout of " + mCurrentPackage.packageName);
   2830             agentErrorCleanup();
   2831             dataChangedImpl(mCurrentPackage.packageName);
   2832         }
   2833 
   2834         void revertAndEndBackup() {
   2835             if (MORE_DEBUG) Slog.i(TAG, "Reverting backup queue - restaging everything");
   2836             addBackupTrace("transport error; reverting");
   2837             for (BackupRequest request : mOriginalQueue) {
   2838                 dataChangedImpl(request.packageName);
   2839             }
   2840             // We also want to reset the backup schedule based on whatever
   2841             // the transport suggests by way of retry/backoff time.
   2842             restartBackupAlarm();
   2843         }
   2844 
   2845         void agentErrorCleanup() {
   2846             mBackupDataName.delete();
   2847             mNewStateName.delete();
   2848             clearAgentState();
   2849 
   2850             executeNextState(mQueue.isEmpty() ? BackupState.FINAL : BackupState.RUNNING_QUEUE);
   2851         }
   2852 
   2853         // Cleanup common to both success and failure cases
   2854         void clearAgentState() {
   2855             try { if (mSavedState != null) mSavedState.close(); } catch (IOException e) {}
   2856             try { if (mBackupData != null) mBackupData.close(); } catch (IOException e) {}
   2857             try { if (mNewState != null) mNewState.close(); } catch (IOException e) {}
   2858             synchronized (mCurrentOpLock) {
   2859                 // Current-operation callback handling requires the validity of these various
   2860                 // bits of internal state as an invariant of the operation still being live.
   2861                 // This means we make sure to clear all of the state in unison inside the lock.
   2862                 mCurrentOperations.clear();
   2863                 mSavedState = mBackupData = mNewState = null;
   2864             }
   2865 
   2866             // If this was a pseudopackage there's no associated Activity Manager state
   2867             if (mCurrentPackage.applicationInfo != null) {
   2868                 addBackupTrace("unbinding " + mCurrentPackage.packageName);
   2869                 try {  // unbind even on timeout, just in case
   2870                     mActivityManager.unbindBackupAgent(mCurrentPackage.applicationInfo);
   2871                 } catch (RemoteException e) { /* can't happen; activity manager is local */ }
   2872             }
   2873         }
   2874 
   2875         void restartBackupAlarm() {
   2876             addBackupTrace("setting backup trigger");
   2877             synchronized (mQueueLock) {
   2878                 try {
   2879                     startBackupAlarmsLocked(mTransport.requestBackupTime());
   2880                 } catch (RemoteException e) { /* cannot happen */ }
   2881             }
   2882         }
   2883 
   2884         void executeNextState(BackupState nextState) {
   2885             if (MORE_DEBUG) Slog.i(TAG, " => executing next step on "
   2886                     + this + " nextState=" + nextState);
   2887             addBackupTrace("executeNextState => " + nextState);
   2888             mCurrentState = nextState;
   2889             Message msg = mBackupHandler.obtainMessage(MSG_BACKUP_RESTORE_STEP, this);
   2890             mBackupHandler.sendMessage(msg);
   2891         }
   2892     }
   2893 
   2894 
   2895     // ----- Full backup/restore to a file/socket -----
   2896 
   2897     class FullBackupObbConnection implements ServiceConnection {
   2898         volatile IObbBackupService mService;
   2899 
   2900         FullBackupObbConnection() {
   2901             mService = null;
   2902         }
   2903 
   2904         public void establish() {
   2905             if (DEBUG) Slog.i(TAG, "Initiating bind of OBB service on " + this);
   2906             Intent obbIntent = new Intent().setComponent(new ComponentName(
   2907                     "com.android.sharedstoragebackup",
   2908                     "com.android.sharedstoragebackup.ObbBackupService"));
   2909             BackupManagerService.this.mContext.bindService(
   2910                     obbIntent, this, Context.BIND_AUTO_CREATE);
   2911         }
   2912 
   2913         public void tearDown() {
   2914             BackupManagerService.this.mContext.unbindService(this);
   2915         }
   2916 
   2917         public boolean backupObbs(PackageInfo pkg, OutputStream out) {
   2918             boolean success = false;
   2919             waitForConnection();
   2920 
   2921             ParcelFileDescriptor[] pipes = null;
   2922             try {
   2923                 pipes = ParcelFileDescriptor.createPipe();
   2924                 int token = generateToken();
   2925                 prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL, null);
   2926                 mService.backupObbs(pkg.packageName, pipes[1], token, mBackupManagerBinder);
   2927                 routeSocketDataToOutput(pipes[0], out);
   2928                 success = waitUntilOperationComplete(token);
   2929             } catch (Exception e) {
   2930                 Slog.w(TAG, "Unable to back up OBBs for " + pkg, e);
   2931             } finally {
   2932                 try {
   2933                     out.flush();
   2934                     if (pipes != null) {
   2935                         if (pipes[0] != null) pipes[0].close();
   2936                         if (pipes[1] != null) pipes[1].close();
   2937                     }
   2938                 } catch (IOException e) {
   2939                     Slog.w(TAG, "I/O error closing down OBB backup", e);
   2940                 }
   2941             }
   2942             return success;
   2943         }
   2944 
   2945         public void restoreObbFile(String pkgName, ParcelFileDescriptor data,
   2946                 long fileSize, int type, String path, long mode, long mtime,
   2947                 int token, IBackupManager callbackBinder) {
   2948             waitForConnection();
   2949 
   2950             try {
   2951                 mService.restoreObbFile(pkgName, data, fileSize, type, path, mode, mtime,
   2952                         token, callbackBinder);
   2953             } catch (Exception e) {
   2954                 Slog.w(TAG, "Unable to restore OBBs for " + pkgName, e);
   2955             }
   2956         }
   2957 
   2958         private void waitForConnection() {
   2959             synchronized (this) {
   2960                 while (mService == null) {
   2961                     if (DEBUG) Slog.i(TAG, "...waiting for OBB service binding...");
   2962                     try {
   2963                         this.wait();
   2964                     } catch (InterruptedException e) { /* never interrupted */ }
   2965                 }
   2966                 if (DEBUG) Slog.i(TAG, "Connected to OBB service; continuing");
   2967             }
   2968         }
   2969 
   2970         @Override
   2971         public void onServiceConnected(ComponentName name, IBinder service) {
   2972             synchronized (this) {
   2973                 mService = IObbBackupService.Stub.asInterface(service);
   2974                 if (DEBUG) Slog.i(TAG, "OBB service connection " + mService
   2975                         + " connected on " + this);
   2976                 this.notifyAll();
   2977             }
   2978         }
   2979 
   2980         @Override
   2981         public void onServiceDisconnected(ComponentName name) {
   2982             synchronized (this) {
   2983                 mService = null;
   2984                 if (DEBUG) Slog.i(TAG, "OBB service connection disconnected on " + this);
   2985                 this.notifyAll();
   2986             }
   2987         }
   2988 
   2989     }
   2990 
   2991     private void routeSocketDataToOutput(ParcelFileDescriptor inPipe, OutputStream out)
   2992             throws IOException {
   2993         FileInputStream raw = new FileInputStream(inPipe.getFileDescriptor());
   2994         DataInputStream in = new DataInputStream(raw);
   2995 
   2996         byte[] buffer = new byte[32 * 1024];
   2997         int chunkTotal;
   2998         while ((chunkTotal = in.readInt()) > 0) {
   2999             while (chunkTotal > 0) {
   3000                 int toRead = (chunkTotal > buffer.length) ? buffer.length : chunkTotal;
   3001                 int nRead = in.read(buffer, 0, toRead);
   3002                 out.write(buffer, 0, nRead);
   3003                 chunkTotal -= nRead;
   3004             }
   3005         }
   3006     }
   3007 
   3008     // Core logic for performing one package's full backup, gathering the tarball from the
   3009     // application and emitting it to the designated OutputStream.
   3010     class FullBackupEngine {
   3011         OutputStream mOutput;
   3012         IFullBackupRestoreObserver mObserver;
   3013         File mFilesDir;
   3014         File mManifestFile;
   3015         File mMetadataFile;
   3016         boolean mIncludeApks;
   3017 
   3018         class FullBackupRunner implements Runnable {
   3019             PackageInfo mPackage;
   3020             byte[] mWidgetData;
   3021             IBackupAgent mAgent;
   3022             ParcelFileDescriptor mPipe;
   3023             int mToken;
   3024             boolean mSendApk;
   3025             boolean mWriteManifest;
   3026 
   3027             FullBackupRunner(PackageInfo pack, IBackupAgent agent, ParcelFileDescriptor pipe,
   3028                     int token, boolean sendApk, boolean writeManifest, byte[] widgetData)
   3029                             throws IOException {
   3030                 mPackage = pack;
   3031                 mWidgetData = widgetData;
   3032                 mAgent = agent;
   3033                 mPipe = ParcelFileDescriptor.dup(pipe.getFileDescriptor());
   3034                 mToken = token;
   3035                 mSendApk = sendApk;
   3036                 mWriteManifest = writeManifest;
   3037             }
   3038 
   3039             @Override
   3040             public void run() {
   3041                 try {
   3042                     BackupDataOutput output = new BackupDataOutput(
   3043                             mPipe.getFileDescriptor());
   3044 
   3045                     if (mWriteManifest) {
   3046                         final boolean writeWidgetData = mWidgetData != null;
   3047                         if (MORE_DEBUG) Slog.d(TAG, "Writing manifest for " + mPackage.packageName);
   3048                         writeAppManifest(mPackage, mManifestFile, mSendApk, writeWidgetData);
   3049                         FullBackup.backupToTar(mPackage.packageName, null, null,
   3050                                 mFilesDir.getAbsolutePath(),
   3051                                 mManifestFile.getAbsolutePath(),
   3052                                 output);
   3053                         mManifestFile.delete();
   3054 
   3055                         // We only need to write a metadata file if we have widget data to stash
   3056                         if (writeWidgetData) {
   3057                             writeMetadata(mPackage, mMetadataFile, mWidgetData);
   3058                             FullBackup.backupToTar(mPackage.packageName, null, null,
   3059                                     mFilesDir.getAbsolutePath(),
   3060                                     mMetadataFile.getAbsolutePath(),
   3061                                     output);
   3062                             mMetadataFile.delete();
   3063                         }
   3064                     }
   3065 
   3066                     if (mSendApk) {
   3067                         writeApkToBackup(mPackage, output);
   3068                     }
   3069 
   3070                     if (DEBUG) Slog.d(TAG, "Calling doFullBackup() on " + mPackage.packageName);
   3071                     prepareOperationTimeout(mToken, TIMEOUT_FULL_BACKUP_INTERVAL, null);
   3072                     mAgent.doFullBackup(mPipe, mToken, mBackupManagerBinder);
   3073                 } catch (IOException e) {
   3074                     Slog.e(TAG, "Error running full backup for " + mPackage.packageName);
   3075                 } catch (RemoteException e) {
   3076                     Slog.e(TAG, "Remote agent vanished during full backup of "
   3077                             + mPackage.packageName);
   3078                 } finally {
   3079                     try {
   3080                         mPipe.close();
   3081                     } catch (IOException e) {}
   3082                 }
   3083             }
   3084         }
   3085 
   3086         FullBackupEngine(OutputStream output, String packageName, boolean alsoApks) {
   3087             mOutput = output;
   3088             mIncludeApks = alsoApks;
   3089             mFilesDir = new File("/data/system");
   3090             mManifestFile = new File(mFilesDir, BACKUP_MANIFEST_FILENAME);
   3091             mMetadataFile = new File(mFilesDir, BACKUP_METADATA_FILENAME);
   3092         }
   3093 
   3094 
   3095         public int backupOnePackage(PackageInfo pkg) throws RemoteException {
   3096             int result = BackupTransport.TRANSPORT_OK;
   3097             Slog.d(TAG, "Binding to full backup agent : " + pkg.packageName);
   3098 
   3099             IBackupAgent agent = bindToAgentSynchronous(pkg.applicationInfo,
   3100                     IApplicationThread.BACKUP_MODE_FULL);
   3101             if (agent != null) {
   3102                 ParcelFileDescriptor[] pipes = null;
   3103                 try {
   3104                     pipes = ParcelFileDescriptor.createPipe();
   3105 
   3106                     ApplicationInfo app = pkg.applicationInfo;
   3107                     final boolean isSharedStorage = pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE);
   3108                     final boolean sendApk = mIncludeApks
   3109                             && !isSharedStorage
   3110                             && ((app.flags & ApplicationInfo.FLAG_FORWARD_LOCK) == 0)
   3111                             && ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0 ||
   3112                                 (app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
   3113 
   3114                     byte[] widgetBlob = AppWidgetBackupBridge.getWidgetState(pkg.packageName,
   3115                             UserHandle.USER_OWNER);
   3116 
   3117                     final int token = generateToken();
   3118                     FullBackupRunner runner = new FullBackupRunner(pkg, agent, pipes[1],
   3119                             token, sendApk, !isSharedStorage, widgetBlob);
   3120                     pipes[1].close();   // the runner has dup'd it
   3121                     pipes[1] = null;
   3122                     Thread t = new Thread(runner, "app-data-runner");
   3123                     t.start();
   3124 
   3125                     // Now pull data from the app and stuff it into the output
   3126                     try {
   3127                         routeSocketDataToOutput(pipes[0], mOutput);
   3128                     } catch (IOException e) {
   3129                         Slog.i(TAG, "Caught exception reading from agent", e);
   3130                         result = BackupTransport.AGENT_ERROR;
   3131                     }
   3132 
   3133                     if (!waitUntilOperationComplete(token)) {
   3134                         Slog.e(TAG, "Full backup failed on package " + pkg.packageName);
   3135                         result = BackupTransport.AGENT_ERROR;
   3136                     } else {
   3137                         if (DEBUG) Slog.d(TAG, "Full package backup success: " + pkg.packageName);
   3138                     }
   3139 
   3140                 } catch (IOException e) {
   3141                     Slog.e(TAG, "Error backing up " + pkg.packageName, e);
   3142                     result = BackupTransport.AGENT_ERROR;
   3143                 } finally {
   3144                     try {
   3145                         // flush after every package
   3146                         mOutput.flush();
   3147                         if (pipes != null) {
   3148                             if (pipes[0] != null) pipes[0].close();
   3149                             if (pipes[1] != null) pipes[1].close();
   3150                         }
   3151                     } catch (IOException e) {
   3152                         Slog.w(TAG, "Error bringing down backup stack");
   3153                         result = BackupTransport.TRANSPORT_ERROR;
   3154                     }
   3155                 }
   3156             } else {
   3157                 Slog.w(TAG, "Unable to bind to full agent for " + pkg.packageName);
   3158                 result = BackupTransport.AGENT_ERROR;
   3159             }
   3160             tearDown(pkg);
   3161             return result;
   3162         }
   3163 
   3164         private void writeApkToBackup(PackageInfo pkg, BackupDataOutput output) {
   3165             // Forward-locked apps, system-bundled .apks, etc are filtered out before we get here
   3166             // TODO: handle backing up split APKs
   3167             final String appSourceDir = pkg.applicationInfo.getBaseCodePath();
   3168             final String apkDir = new File(appSourceDir).getParent();
   3169             FullBackup.backupToTar(pkg.packageName, FullBackup.APK_TREE_TOKEN, null,
   3170                     apkDir, appSourceDir, output);
   3171 
   3172             // TODO: migrate this to SharedStorageBackup, since AID_SYSTEM
   3173             // doesn't have access to external storage.
   3174 
   3175             // Save associated .obb content if it exists and we did save the apk
   3176             // check for .obb and save those too
   3177             final UserEnvironment userEnv = new UserEnvironment(UserHandle.USER_OWNER);
   3178             final File obbDir = userEnv.buildExternalStorageAppObbDirs(pkg.packageName)[0];
   3179             if (obbDir != null) {
   3180                 if (MORE_DEBUG) Log.i(TAG, "obb dir: " + obbDir.getAbsolutePath());
   3181                 File[] obbFiles = obbDir.listFiles();
   3182                 if (obbFiles != null) {
   3183                     final String obbDirName = obbDir.getAbsolutePath();
   3184                     for (File obb : obbFiles) {
   3185                         FullBackup.backupToTar(pkg.packageName, FullBackup.OBB_TREE_TOKEN, null,
   3186                                 obbDirName, obb.getAbsolutePath(), output);
   3187                     }
   3188                 }
   3189             }
   3190         }
   3191 
   3192         private void writeAppManifest(PackageInfo pkg, File manifestFile,
   3193                 boolean withApk, boolean withWidgets) throws IOException {
   3194             // Manifest format. All data are strings ending in LF:
   3195             //     BACKUP_MANIFEST_VERSION, currently 1
   3196             //
   3197             // Version 1:
   3198             //     package name
   3199             //     package's versionCode
   3200             //     platform versionCode
   3201             //     getInstallerPackageName() for this package (maybe empty)
   3202             //     boolean: "1" if archive includes .apk; any other string means not
   3203             //     number of signatures == N
   3204             // N*:    signature byte array in ascii format per Signature.toCharsString()
   3205             StringBuilder builder = new StringBuilder(4096);
   3206             StringBuilderPrinter printer = new StringBuilderPrinter(builder);
   3207 
   3208             printer.println(Integer.toString(BACKUP_MANIFEST_VERSION));
   3209             printer.println(pkg.packageName);
   3210             printer.println(Integer.toString(pkg.versionCode));
   3211             printer.println(Integer.toString(Build.VERSION.SDK_INT));
   3212 
   3213             String installerName = mPackageManager.getInstallerPackageName(pkg.packageName);
   3214             printer.println((installerName != null) ? installerName : "");
   3215 
   3216             printer.println(withApk ? "1" : "0");
   3217             if (pkg.signatures == null) {
   3218                 printer.println("0");
   3219             } else {
   3220                 printer.println(Integer.toString(pkg.signatures.length));
   3221                 for (Signature sig : pkg.signatures) {
   3222                     printer.println(sig.toCharsString());
   3223                 }
   3224             }
   3225 
   3226             FileOutputStream outstream = new FileOutputStream(manifestFile);
   3227             outstream.write(builder.toString().getBytes());
   3228             outstream.close();
   3229 
   3230             // We want the manifest block in the archive stream to be idempotent:
   3231             // each time we generate a backup stream for the app, we want the manifest
   3232             // block to be identical.  The underlying tar mechanism sees it as a file,
   3233             // though, and will propagate its mtime, causing the tar header to vary.
   3234             // Avoid this problem by pinning the mtime to zero.
   3235             manifestFile.setLastModified(0);
   3236         }
   3237 
   3238         // Widget metadata format. All header entries are strings ending in LF:
   3239         //
   3240         // Version 1 header:
   3241         //     BACKUP_METADATA_VERSION, currently "1"
   3242         //     package name
   3243         //
   3244         // File data (all integers are binary in network byte order)
   3245         // *N: 4 : integer token identifying which metadata blob
   3246         //     4 : integer size of this blob = N
   3247         //     N : raw bytes of this metadata blob
   3248         //
   3249         // Currently understood blobs (always in network byte order):
   3250         //
   3251         //     widgets : metadata token = 0x01FFED01 (BACKUP_WIDGET_METADATA_TOKEN)
   3252         //
   3253         // Unrecognized blobs are *ignored*, not errors.
   3254         private void writeMetadata(PackageInfo pkg, File destination, byte[] widgetData)
   3255                 throws IOException {
   3256             StringBuilder b = new StringBuilder(512);
   3257             StringBuilderPrinter printer = new StringBuilderPrinter(b);
   3258             printer.println(Integer.toString(BACKUP_METADATA_VERSION));
   3259             printer.println(pkg.packageName);
   3260 
   3261             FileOutputStream fout = new FileOutputStream(destination);
   3262             BufferedOutputStream bout = new BufferedOutputStream(fout);
   3263             DataOutputStream out = new DataOutputStream(bout);
   3264             bout.write(b.toString().getBytes());    // bypassing DataOutputStream
   3265 
   3266             if (widgetData != null && widgetData.length > 0) {
   3267                 out.writeInt(BACKUP_WIDGET_METADATA_TOKEN);
   3268                 out.writeInt(widgetData.length);
   3269                 out.write(widgetData);
   3270             }
   3271             bout.flush();
   3272             out.close();
   3273 
   3274             // As with the manifest file, guarantee idempotence of the archive metadata
   3275             // for the widget block by using a fixed mtime on the transient file.
   3276             destination.setLastModified(0);
   3277         }
   3278 
   3279         private void tearDown(PackageInfo pkg) {
   3280             if (pkg != null) {
   3281                 final ApplicationInfo app = pkg.applicationInfo;
   3282                 if (app != null) {
   3283                     try {
   3284                         // unbind and tidy up even on timeout or failure, just in case
   3285                         mActivityManager.unbindBackupAgent(app);
   3286 
   3287                         // The agent was running with a stub Application object, so shut it down.
   3288                         if (app.uid != Process.SYSTEM_UID
   3289                                 && app.uid != Process.PHONE_UID) {
   3290                             if (MORE_DEBUG) Slog.d(TAG, "Backup complete, killing host process");
   3291                             mActivityManager.killApplicationProcess(app.processName, app.uid);
   3292                         } else {
   3293                             if (MORE_DEBUG) Slog.d(TAG, "Not killing after backup: " + app.processName);
   3294                         }
   3295                     } catch (RemoteException e) {
   3296                         Slog.d(TAG, "Lost app trying to shut down");
   3297                     }
   3298                 }
   3299             }
   3300         }
   3301     }
   3302 
   3303     // Generic driver skeleton for full backup operations
   3304     abstract class FullBackupTask implements Runnable {
   3305         IFullBackupRestoreObserver mObserver;
   3306 
   3307         FullBackupTask(IFullBackupRestoreObserver observer) {
   3308             mObserver = observer;
   3309         }
   3310 
   3311         // wrappers for observer use
   3312         final void sendStartBackup() {
   3313             if (mObserver != null) {
   3314                 try {
   3315                     mObserver.onStartBackup();
   3316                 } catch (RemoteException e) {
   3317                     Slog.w(TAG, "full backup observer went away: startBackup");
   3318                     mObserver = null;
   3319                 }
   3320             }
   3321         }
   3322 
   3323         final void sendOnBackupPackage(String name) {
   3324             if (mObserver != null) {
   3325                 try {
   3326                     // TODO: use a more user-friendly name string
   3327                     mObserver.onBackupPackage(name);
   3328                 } catch (RemoteException e) {
   3329                     Slog.w(TAG, "full backup observer went away: backupPackage");
   3330                     mObserver = null;
   3331                 }
   3332             }
   3333         }
   3334 
   3335         final void sendEndBackup() {
   3336             if (mObserver != null) {
   3337                 try {
   3338                     mObserver.onEndBackup();
   3339                 } catch (RemoteException e) {
   3340                     Slog.w(TAG, "full backup observer went away: endBackup");
   3341                     mObserver = null;
   3342                 }
   3343             }
   3344         }
   3345     }
   3346 
   3347     boolean deviceIsEncrypted() {
   3348         try {
   3349             return mMountService.getEncryptionState()
   3350                      != IMountService.ENCRYPTION_STATE_NONE
   3351                 && mMountService.getPasswordType()
   3352                      != StorageManager.CRYPT_TYPE_DEFAULT;
   3353         } catch (Exception e) {
   3354             // If we can't talk to the mount service we have a serious problem; fail
   3355             // "secure" i.e. assuming that the device is encrypted.
   3356             Slog.e(TAG, "Unable to communicate with mount service: " + e.getMessage());
   3357             return true;
   3358         }
   3359     }
   3360 
   3361     // Full backup task variant used for adb backup
   3362     class PerformAdbBackupTask extends FullBackupTask {
   3363         FullBackupEngine mBackupEngine;
   3364         final AtomicBoolean mLatch;
   3365 
   3366         ParcelFileDescriptor mOutputFile;
   3367         DeflaterOutputStream mDeflater;
   3368         boolean mIncludeApks;
   3369         boolean mIncludeObbs;
   3370         boolean mIncludeShared;
   3371         boolean mDoWidgets;
   3372         boolean mAllApps;
   3373         boolean mIncludeSystem;
   3374         boolean mCompress;
   3375         ArrayList<String> mPackages;
   3376         String mCurrentPassword;
   3377         String mEncryptPassword;
   3378 
   3379         PerformAdbBackupTask(ParcelFileDescriptor fd, IFullBackupRestoreObserver observer,
   3380                 boolean includeApks, boolean includeObbs, boolean includeShared,
   3381                 boolean doWidgets, String curPassword, String encryptPassword, boolean doAllApps,
   3382                 boolean doSystem, boolean doCompress, String[] packages, AtomicBoolean latch) {
   3383             super(observer);
   3384             mLatch = latch;
   3385 
   3386             mOutputFile = fd;
   3387             mIncludeApks = includeApks;
   3388             mIncludeObbs = includeObbs;
   3389             mIncludeShared = includeShared;
   3390             mDoWidgets = doWidgets;
   3391             mAllApps = doAllApps;
   3392             mIncludeSystem = doSystem;
   3393             mPackages = (packages == null)
   3394                     ? new ArrayList<String>()
   3395                     : new ArrayList<String>(Arrays.asList(packages));
   3396             mCurrentPassword = curPassword;
   3397             // when backing up, if there is a current backup password, we require that
   3398             // the user use a nonempty encryption password as well.  if one is supplied
   3399             // in the UI we use that, but if the UI was left empty we fall back to the
   3400             // current backup password (which was supplied by the user as well).
   3401             if (encryptPassword == null || "".equals(encryptPassword)) {
   3402                 mEncryptPassword = curPassword;
   3403             } else {
   3404                 mEncryptPassword = encryptPassword;
   3405             }
   3406             mCompress = doCompress;
   3407         }
   3408 
   3409         void addPackagesToSet(TreeMap<String, PackageInfo> set, List<String> pkgNames) {
   3410             for (String pkgName : pkgNames) {
   3411                 if (!set.containsKey(pkgName)) {
   3412                     try {
   3413                         PackageInfo info = mPackageManager.getPackageInfo(pkgName,
   3414                                 PackageManager.GET_SIGNATURES);
   3415                         set.put(pkgName, info);
   3416                     } catch (NameNotFoundException e) {
   3417                         Slog.w(TAG, "Unknown package " + pkgName + ", skipping");
   3418                     }
   3419                 }
   3420             }
   3421         }
   3422 
   3423         private OutputStream emitAesBackupHeader(StringBuilder headerbuf,
   3424                 OutputStream ofstream) throws Exception {
   3425             // User key will be used to encrypt the master key.
   3426             byte[] newUserSalt = randomBytes(PBKDF2_SALT_SIZE);
   3427             SecretKey userKey = buildPasswordKey(PBKDF_CURRENT, mEncryptPassword, newUserSalt,
   3428                     PBKDF2_HASH_ROUNDS);
   3429 
   3430             // the master key is random for each backup
   3431             byte[] masterPw = new byte[256 / 8];
   3432             mRng.nextBytes(masterPw);
   3433             byte[] checksumSalt = randomBytes(PBKDF2_SALT_SIZE);
   3434 
   3435             // primary encryption of the datastream with the random key
   3436             Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
   3437             SecretKeySpec masterKeySpec = new SecretKeySpec(masterPw, "AES");
   3438             c.init(Cipher.ENCRYPT_MODE, masterKeySpec);
   3439             OutputStream finalOutput = new CipherOutputStream(ofstream, c);
   3440 
   3441             // line 4: name of encryption algorithm
   3442             headerbuf.append(ENCRYPTION_ALGORITHM_NAME);
   3443             headerbuf.append('\n');
   3444             // line 5: user password salt [hex]
   3445             headerbuf.append(byteArrayToHex(newUserSalt));
   3446             headerbuf.append('\n');
   3447             // line 6: master key checksum salt [hex]
   3448             headerbuf.append(byteArrayToHex(checksumSalt));
   3449             headerbuf.append('\n');
   3450             // line 7: number of PBKDF2 rounds used [decimal]
   3451             headerbuf.append(PBKDF2_HASH_ROUNDS);
   3452             headerbuf.append('\n');
   3453 
   3454             // line 8: IV of the user key [hex]
   3455             Cipher mkC = Cipher.getInstance("AES/CBC/PKCS5Padding");
   3456             mkC.init(Cipher.ENCRYPT_MODE, userKey);
   3457 
   3458             byte[] IV = mkC.getIV();
   3459             headerbuf.append(byteArrayToHex(IV));
   3460             headerbuf.append('\n');
   3461 
   3462             // line 9: master IV + key blob, encrypted by the user key [hex].  Blob format:
   3463             //    [byte] IV length = Niv
   3464             //    [array of Niv bytes] IV itself
   3465             //    [byte] master key length = Nmk
   3466             //    [array of Nmk bytes] master key itself
   3467             //    [byte] MK checksum hash length = Nck
   3468             //    [array of Nck bytes] master key checksum hash
   3469             //
   3470             // The checksum is the (master key + checksum salt), run through the
   3471             // stated number of PBKDF2 rounds
   3472             IV = c.getIV();
   3473             byte[] mk = masterKeySpec.getEncoded();
   3474             byte[] checksum = makeKeyChecksum(PBKDF_CURRENT, masterKeySpec.getEncoded(),
   3475                     checksumSalt, PBKDF2_HASH_ROUNDS);
   3476 
   3477             ByteArrayOutputStream blob = new ByteArrayOutputStream(IV.length + mk.length
   3478                     + checksum.length + 3);
   3479             DataOutputStream mkOut = new DataOutputStream(blob);
   3480             mkOut.writeByte(IV.length);
   3481             mkOut.write(IV);
   3482             mkOut.writeByte(mk.length);
   3483             mkOut.write(mk);
   3484             mkOut.writeByte(checksum.length);
   3485             mkOut.write(checksum);
   3486             mkOut.flush();
   3487             byte[] encryptedMk = mkC.doFinal(blob.toByteArray());
   3488             headerbuf.append(byteArrayToHex(encryptedMk));
   3489             headerbuf.append('\n');
   3490 
   3491             return finalOutput;
   3492         }
   3493 
   3494         private void finalizeBackup(OutputStream out) {
   3495             try {
   3496                 // A standard 'tar' EOF sequence: two 512-byte blocks of all zeroes.
   3497                 byte[] eof = new byte[512 * 2]; // newly allocated == zero filled
   3498                 out.write(eof);
   3499             } catch (IOException e) {
   3500                 Slog.w(TAG, "Error attempting to finalize backup stream");
   3501             }
   3502         }
   3503 
   3504         @Override
   3505         public void run() {
   3506             Slog.i(TAG, "--- Performing full-dataset adb backup ---");
   3507 
   3508             TreeMap<String, PackageInfo> packagesToBackup = new TreeMap<String, PackageInfo>();
   3509             FullBackupObbConnection obbConnection = new FullBackupObbConnection();
   3510             obbConnection.establish();  // we'll want this later
   3511 
   3512             sendStartBackup();
   3513 
   3514             // doAllApps supersedes the package set if any
   3515             if (mAllApps) {
   3516                 List<PackageInfo> allPackages = mPackageManager.getInstalledPackages(
   3517                         PackageManager.GET_SIGNATURES);
   3518                 for (int i = 0; i < allPackages.size(); i++) {
   3519                     PackageInfo pkg = allPackages.get(i);
   3520                     // Exclude system apps if we've been asked to do so
   3521                     if (mIncludeSystem == true
   3522                             || ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0)) {
   3523                         packagesToBackup.put(pkg.packageName, pkg);
   3524                     }
   3525                 }
   3526             }
   3527 
   3528             // If we're doing widget state as well, ensure that we have all the involved
   3529             // host & provider packages in the set
   3530             if (mDoWidgets) {
   3531                 List<String> pkgs =
   3532                         AppWidgetBackupBridge.getWidgetParticipants(UserHandle.USER_OWNER);
   3533                 if (pkgs != null) {
   3534                     if (MORE_DEBUG) {
   3535                         Slog.i(TAG, "Adding widget participants to backup set:");
   3536                         StringBuilder sb = new StringBuilder(128);
   3537                         sb.append("   ");
   3538                         for (String s : pkgs) {
   3539                             sb.append(' ');
   3540                             sb.append(s);
   3541                         }
   3542                         Slog.i(TAG, sb.toString());
   3543                     }
   3544                     addPackagesToSet(packagesToBackup, pkgs);
   3545                 }
   3546             }
   3547 
   3548             // Now process the command line argument packages, if any. Note that explicitly-
   3549             // named system-partition packages will be included even if includeSystem was
   3550             // set to false.
   3551             if (mPackages != null) {
   3552                 addPackagesToSet(packagesToBackup, mPackages);
   3553             }
   3554 
   3555             // Now we cull any inapplicable / inappropriate packages from the set.  This
   3556             // includes the special shared-storage agent package; we handle that one
   3557             // explicitly at the end of the backup pass.
   3558             Iterator<Entry<String, PackageInfo>> iter = packagesToBackup.entrySet().iterator();
   3559             while (iter.hasNext()) {
   3560                 PackageInfo pkg = iter.next().getValue();
   3561                 if (!appIsEligibleForBackup(pkg.applicationInfo)) {
   3562                     iter.remove();
   3563                 }
   3564             }
   3565 
   3566             // flatten the set of packages now so we can explicitly control the ordering
   3567             ArrayList<PackageInfo> backupQueue =
   3568                     new ArrayList<PackageInfo>(packagesToBackup.values());
   3569             FileOutputStream ofstream = new FileOutputStream(mOutputFile.getFileDescriptor());
   3570             OutputStream out = null;
   3571 
   3572             PackageInfo pkg = null;
   3573             try {
   3574                 boolean encrypting = (mEncryptPassword != null && mEncryptPassword.length() > 0);
   3575 
   3576                 // Only allow encrypted backups of encrypted devices
   3577                 if (deviceIsEncrypted() && !encrypting) {
   3578                     Slog.e(TAG, "Unencrypted backup of encrypted device; aborting");
   3579                     return;
   3580                 }
   3581 
   3582                 OutputStream finalOutput = ofstream;
   3583 
   3584                 // Verify that the given password matches the currently-active
   3585                 // backup password, if any
   3586                 if (!backupPasswordMatches(mCurrentPassword)) {
   3587                     if (DEBUG) Slog.w(TAG, "Backup password mismatch; aborting");
   3588                     return;
   3589                 }
   3590 
   3591                 // Write the global file header.  All strings are UTF-8 encoded; lines end
   3592                 // with a '\n' byte.  Actual backup data begins immediately following the
   3593                 // final '\n'.
   3594                 //
   3595                 // line 1: "ANDROID BACKUP"
   3596                 // line 2: backup file format version, currently "2"
   3597                 // line 3: compressed?  "0" if not compressed, "1" if compressed.
   3598                 // line 4: name of encryption algorithm [currently only "none" or "AES-256"]
   3599                 //
   3600                 // When line 4 is not "none", then additional header data follows:
   3601                 //
   3602                 // line 5: user password salt [hex]
   3603                 // line 6: master key checksum salt [hex]
   3604                 // line 7: number of PBKDF2 rounds to use (same for user & master) [decimal]
   3605                 // line 8: IV of the user key [hex]
   3606                 // line 9: master key blob [hex]
   3607                 //     IV of the master key, master key itself, master key checksum hash
   3608                 //
   3609                 // The master key checksum is the master key plus its checksum salt, run through
   3610                 // 10k rounds of PBKDF2.  This is used to verify that the user has supplied the
   3611                 // correct password for decrypting the archive:  the master key decrypted from
   3612                 // the archive using the user-supplied password is also run through PBKDF2 in
   3613                 // this way, and if the result does not match the checksum as stored in the
   3614                 // archive, then we know that the user-supplied password does not match the
   3615                 // archive's.
   3616                 StringBuilder headerbuf = new StringBuilder(1024);
   3617 
   3618                 headerbuf.append(BACKUP_FILE_HEADER_MAGIC);
   3619                 headerbuf.append(BACKUP_FILE_VERSION); // integer, no trailing \n
   3620                 headerbuf.append(mCompress ? "\n1\n" : "\n0\n");
   3621 
   3622                 try {
   3623                     // Set up the encryption stage if appropriate, and emit the correct header
   3624                     if (encrypting) {
   3625                         finalOutput = emitAesBackupHeader(headerbuf, finalOutput);
   3626                     } else {
   3627                         headerbuf.append("none\n");
   3628                     }
   3629 
   3630                     byte[] header = headerbuf.toString().getBytes("UTF-8");
   3631                     ofstream.write(header);
   3632 
   3633                     // Set up the compression stage feeding into the encryption stage (if any)
   3634                     if (mCompress) {
   3635                         Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION);
   3636                         finalOutput = new DeflaterOutputStream(finalOutput, deflater, true);
   3637                     }
   3638 
   3639                     out = finalOutput;
   3640                 } catch (Exception e) {
   3641                     // Should never happen!
   3642                     Slog.e(TAG, "Unable to emit archive header", e);
   3643                     return;
   3644                 }
   3645 
   3646                 // Shared storage if requested
   3647                 if (mIncludeShared) {
   3648                     try {
   3649                         pkg = mPackageManager.getPackageInfo(SHARED_BACKUP_AGENT_PACKAGE, 0);
   3650                         backupQueue.add(pkg);
   3651                     } catch (NameNotFoundException e) {
   3652                         Slog.e(TAG, "Unable to find shared-storage backup handler");
   3653                     }
   3654                 }
   3655 
   3656                 // Now actually run the constructed backup sequence
   3657                 int N = backupQueue.size();
   3658                 for (int i = 0; i < N; i++) {
   3659                     pkg = backupQueue.get(i);
   3660                     final boolean isSharedStorage =
   3661                             pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE);
   3662 
   3663                     mBackupEngine = new FullBackupEngine(out, pkg.packageName, mIncludeApks);
   3664                     sendOnBackupPackage(isSharedStorage ? "Shared storage" : pkg.packageName);
   3665                     mBackupEngine.backupOnePackage(pkg);
   3666 
   3667                     // after the app's agent runs to handle its private filesystem
   3668                     // contents, back up any OBB content it has on its behalf.
   3669                     if (mIncludeObbs) {
   3670                         boolean obbOkay = obbConnection.backupObbs(pkg, out);
   3671                         if (!obbOkay) {
   3672                             throw new RuntimeException("Failure writing OBB stack for " + pkg);
   3673                         }
   3674                     }
   3675                 }
   3676 
   3677                 // Done!
   3678                 finalizeBackup(out);
   3679             } catch (RemoteException e) {
   3680                 Slog.e(TAG, "App died during full backup");
   3681             } catch (Exception e) {
   3682                 Slog.e(TAG, "Internal exception during full backup", e);
   3683             } finally {
   3684                 try {
   3685                     if (out != null) out.close();
   3686                     mOutputFile.close();
   3687                 } catch (IOException e) {
   3688                     /* nothing we can do about this */
   3689                 }
   3690                 synchronized (mCurrentOpLock) {
   3691                     mCurrentOperations.clear();
   3692                 }
   3693                 synchronized (mLatch) {
   3694                     mLatch.set(true);
   3695                     mLatch.notifyAll();
   3696                 }
   3697                 sendEndBackup();
   3698                 obbConnection.tearDown();
   3699                 if (DEBUG) Slog.d(TAG, "Full backup pass complete.");
   3700                 mWakelock.release();
   3701             }
   3702         }
   3703     }
   3704 
   3705     // Full backup task extension used for transport-oriented operation
   3706     class PerformFullTransportBackupTask extends FullBackupTask {
   3707         static final String TAG = "PFTBT";
   3708         ArrayList<PackageInfo> mPackages;
   3709         boolean mUpdateSchedule;
   3710         AtomicBoolean mLatch;
   3711         AtomicBoolean mKeepRunning;     // signal from job scheduler
   3712         FullBackupJob mJob;             // if a scheduled job needs to be finished afterwards
   3713 
   3714         PerformFullTransportBackupTask(IFullBackupRestoreObserver observer,
   3715                 String[] whichPackages, boolean updateSchedule,
   3716                 FullBackupJob runningJob, AtomicBoolean latch) {
   3717             super(observer);
   3718             mUpdateSchedule = updateSchedule;
   3719             mLatch = latch;
   3720             mKeepRunning = new AtomicBoolean(true);
   3721             mJob = runningJob;
   3722             mPackages = new ArrayList<PackageInfo>(whichPackages.length);
   3723 
   3724             for (String pkg : whichPackages) {
   3725                 try {
   3726                     PackageInfo info = mPackageManager.getPackageInfo(pkg,
   3727                             PackageManager.GET_SIGNATURES);
   3728                     if ((info.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0
   3729                             || pkg.equals(SHARED_BACKUP_AGENT_PACKAGE)) {
   3730                         // Cull any packages that have indicated that backups are not permitted,
   3731                         // as well as any explicit mention of the 'special' shared-storage agent
   3732                         // package (we handle that one at the end).
   3733                         if (MORE_DEBUG) {
   3734                             Slog.d(TAG, "Ignoring opted-out package " + pkg);
   3735                         }
   3736                         continue;
   3737                     } else if ((info.applicationInfo.uid < Process.FIRST_APPLICATION_UID)
   3738                             && (info.applicationInfo.backupAgentName == null)) {
   3739                         // Cull any packages that run as system-domain uids but do not define their
   3740                         // own backup agents
   3741                         if (MORE_DEBUG) {
   3742                             Slog.d(TAG, "Ignoring non-agent system package " + pkg);
   3743                         }
   3744                         continue;
   3745                     }
   3746                     mPackages.add(info);
   3747                 } catch (NameNotFoundException e) {
   3748                     Slog.i(TAG, "Requested package " + pkg + " not found; ignoring");
   3749                 }
   3750             }
   3751         }
   3752 
   3753         public void setRunning(boolean running) {
   3754             mKeepRunning.set(running);
   3755         }
   3756 
   3757         @Override
   3758         public void run() {
   3759             // data from the app, passed to us for bridging to the transport
   3760             ParcelFileDescriptor[] enginePipes = null;
   3761 
   3762             // Pipe through which we write data to the transport
   3763             ParcelFileDescriptor[] transportPipes = null;
   3764 
   3765             PackageInfo currentPackage;
   3766 
   3767             try {
   3768                 IBackupTransport transport = getTransport(mCurrentTransport);
   3769                 if (transport == null) {
   3770                     Slog.w(TAG, "Transport not present; full data backup not performed");
   3771                     return;
   3772                 }
   3773 
   3774                 // Set up to send data to the transport
   3775                 final int N = mPackages.size();
   3776                 for (int i = 0; i < N; i++) {
   3777                     currentPackage = mPackages.get(i);
   3778                     if (DEBUG) {
   3779                         Slog.i(TAG, "Initiating full-data transport backup of "
   3780                                 + currentPackage.packageName);
   3781                     }
   3782                     EventLog.writeEvent(EventLogTags.FULL_BACKUP_PACKAGE,
   3783                             currentPackage.packageName);
   3784 
   3785                     transportPipes = ParcelFileDescriptor.createPipe();
   3786 
   3787                     // Tell the transport the data's coming
   3788                     int result = transport.performFullBackup(currentPackage,
   3789                             transportPipes[0]);
   3790                     if (result == BackupTransport.TRANSPORT_OK) {
   3791                         // The transport has its own copy of the read end of the pipe,
   3792                         // so close ours now
   3793                         transportPipes[0].close();
   3794                         transportPipes[0] = null;
   3795 
   3796                         // Now set up the backup engine / data source end of things
   3797                         enginePipes = ParcelFileDescriptor.createPipe();
   3798                         AtomicBoolean runnerLatch = new AtomicBoolean(false);
   3799                         SinglePackageBackupRunner backupRunner =
   3800                                 new SinglePackageBackupRunner(enginePipes[1], currentPackage,
   3801                                         runnerLatch);
   3802                         // The runner dup'd the pipe half, so we close it here
   3803                         enginePipes[1].close();
   3804                         enginePipes[1] = null;
   3805 
   3806                         // Spin off the runner to fetch the app's data and pipe it
   3807                         // into the engine pipes
   3808                         (new Thread(backupRunner, "package-backup-bridge")).start();
   3809 
   3810                         // Read data off the engine pipe and pass it to the transport
   3811                         // pipe until we hit EOD on the input stream.
   3812                         FileInputStream in = new FileInputStream(
   3813                                 enginePipes[0].getFileDescriptor());
   3814                         FileOutputStream out = new FileOutputStream(
   3815                                 transportPipes[1].getFileDescriptor());
   3816                         byte[] buffer = new byte[8192];
   3817                         int nRead = 0;
   3818                         do {
   3819                             if (!mKeepRunning.get()) {
   3820                                 if (DEBUG_SCHEDULING) {
   3821                                     Slog.i(TAG, "Full backup task told to stop");
   3822                                 }
   3823                                 break;
   3824                             }
   3825                             nRead = in.read(buffer);
   3826                             if (nRead > 0) {
   3827                                 out.write(buffer, 0, nRead);
   3828                                 result = transport.sendBackupData(nRead);
   3829                             }
   3830                         } while (nRead > 0 && result == BackupTransport.TRANSPORT_OK);
   3831 
   3832                         // If we've lost our running criteria, tell the transport to cancel
   3833                         // and roll back this (partial) backup payload; otherwise tell it
   3834                         // that we've reached the clean finish state.
   3835                         if (!mKeepRunning.get()) {
   3836                             result = BackupTransport.TRANSPORT_ERROR;
   3837                             transport.cancelFullBackup();
   3838                         } else {
   3839                             // If we were otherwise in a good state, now interpret the final
   3840                             // result based on what finishBackup() returns.  If we're in a
   3841                             // failure case already, preserve that result and ignore whatever
   3842                             // finishBackup() reports.
   3843                             final int finishResult = transport.finishBackup();
   3844                             if (result == BackupTransport.TRANSPORT_OK) {
   3845                                 result = finishResult;
   3846                             }
   3847                         }
   3848 
   3849                         if (MORE_DEBUG) {
   3850                             Slog.i(TAG, "Done trying to send backup data: result=" + result);
   3851                         }
   3852 
   3853                         if (result != BackupTransport.TRANSPORT_OK) {
   3854                             Slog.e(TAG, "Error " + result
   3855                                     + " backing up " + currentPackage.packageName);
   3856                         }
   3857                     }
   3858 
   3859                     // Roll this package to the end of the backup queue if we're
   3860                     // in a queue-driven mode (regardless of success/failure)
   3861                     if (mUpdateSchedule) {
   3862                         enqueueFullBackup(currentPackage.packageName,
   3863                                 System.currentTimeMillis());
   3864                     }
   3865 
   3866                     if (result == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
   3867                         if (DEBUG) {
   3868                             Slog.i(TAG, "Transport rejected backup of "
   3869                                     + currentPackage.packageName
   3870                                     + ", skipping");
   3871                         }
   3872                         EventLog.writeEvent(EventLogTags.FULL_BACKUP_AGENT_FAILURE,
   3873                                 currentPackage.packageName, "transport rejected");
   3874                         // do nothing, clean up, and continue looping
   3875                     } else if (result != BackupTransport.TRANSPORT_OK) {
   3876                         if (DEBUG) {
   3877                             Slog.i(TAG, "Transport failed; aborting backup: " + result);
   3878                             EventLog.writeEvent(EventLogTags.FULL_BACKUP_TRANSPORT_FAILURE);
   3879                             return;
   3880                         }
   3881                     } else {
   3882                         // Success!
   3883                         EventLog.writeEvent(EventLogTags.FULL_BACKUP_SUCCESS,
   3884                                 currentPackage.packageName);
   3885                         logBackupComplete(currentPackage.packageName);
   3886                     }
   3887                     cleanUpPipes(transportPipes);
   3888                     cleanUpPipes(enginePipes);
   3889                     currentPackage = null;
   3890                 }
   3891 
   3892                 if (DEBUG) {
   3893                     Slog.i(TAG, "Full backup completed.");
   3894                 }
   3895             } catch (Exception e) {
   3896                 Slog.w(TAG, "Exception trying full transport backup", e);
   3897             } finally {
   3898                 cleanUpPipes(transportPipes);
   3899                 cleanUpPipes(enginePipes);
   3900 
   3901                 if (mJob != null) {
   3902                     mJob.finishBackupPass();
   3903                 }
   3904 
   3905                 synchronized (mQueueLock) {
   3906                     mRunningFullBackupTask = null;
   3907                 }
   3908 
   3909                 synchronized (mLatch) {
   3910                     mLatch.set(true);
   3911                     mLatch.notifyAll();
   3912                 }
   3913 
   3914                 // Now that we're actually done with schedule-driven work, reschedule
   3915                 // the next pass based on the new queue state.
   3916                 if (mUpdateSchedule) {
   3917                     scheduleNextFullBackupJob();
   3918                 }
   3919             }
   3920         }
   3921 
   3922         void cleanUpPipes(ParcelFileDescriptor[] pipes) {
   3923             if (pipes != null) {
   3924                 if (pipes[0] != null) {
   3925                     ParcelFileDescriptor fd = pipes[0];
   3926                     pipes[0] = null;
   3927                     try {
   3928                         fd.close();
   3929                     } catch (IOException e) {
   3930                         Slog.w(TAG, "Unable to close pipe!");
   3931                     }
   3932                 }
   3933                 if (pipes[1] != null) {
   3934                     ParcelFileDescriptor fd = pipes[1];
   3935                     pipes[1] = null;
   3936                     try {
   3937                         fd.close();
   3938                     } catch (IOException e) {
   3939                         Slog.w(TAG, "Unable to close pipe!");
   3940                     }
   3941                 }
   3942             }
   3943         }
   3944 
   3945         // Run the backup and pipe it back to the given socket -- expects to run on
   3946         // a standalone thread.  The  runner owns this half of the pipe, and closes
   3947         // it to indicate EOD to the other end.
   3948         class SinglePackageBackupRunner implements Runnable {
   3949             final ParcelFileDescriptor mOutput;
   3950             final PackageInfo mTarget;
   3951             final AtomicBoolean mLatch;
   3952 
   3953             SinglePackageBackupRunner(ParcelFileDescriptor output, PackageInfo target,
   3954                     AtomicBoolean latch) throws IOException {
   3955                 int oldfd = output.getFd();
   3956                 mOutput = ParcelFileDescriptor.dup(output.getFileDescriptor());
   3957                 mTarget = target;
   3958                 mLatch = latch;
   3959             }
   3960 
   3961             @Override
   3962             public void run() {
   3963                 try {
   3964                     FileOutputStream out = new FileOutputStream(mOutput.getFileDescriptor());
   3965                     FullBackupEngine engine = new FullBackupEngine(out, mTarget.packageName, false);
   3966                     engine.backupOnePackage(mTarget);
   3967                 } catch (Exception e) {
   3968                     Slog.e(TAG, "Exception during full package backup of " + mTarget);
   3969                 } finally {
   3970                     synchronized (mLatch) {
   3971                         mLatch.set(true);
   3972                         mLatch.notifyAll();
   3973                     }
   3974                     try {
   3975                         mOutput.close();
   3976                     } catch (IOException e) {
   3977                         Slog.w(TAG, "Error closing transport pipe in runner");
   3978                     }
   3979                 }
   3980             }
   3981 
   3982         }
   3983     }
   3984 
   3985     // ----- Full-data backup scheduling -----
   3986 
   3987     /**
   3988      * Schedule a job to tell us when it's a good time to run a full backup
   3989      */
   3990     void scheduleNextFullBackupJob() {
   3991         synchronized (mQueueLock) {
   3992             if (mFullBackupQueue.size() > 0) {
   3993                 // schedule the next job at the point in the future when the least-recently
   3994                 // backed up app comes due for backup again; or immediately if it's already
   3995                 // due.
   3996                 long upcomingLastBackup = mFullBackupQueue.get(0).lastBackup;
   3997                 long timeSinceLast = System.currentTimeMillis() - upcomingLastBackup;
   3998                 final long latency = (timeSinceLast < MIN_FULL_BACKUP_INTERVAL)
   3999                         ? (MIN_FULL_BACKUP_INTERVAL - timeSinceLast) : 0;
   4000                 Runnable r = new Runnable() {
   4001                     @Override public void run() {
   4002                         FullBackupJob.schedule(mContext, latency);
   4003                     }
   4004                 };
   4005                 mBackupHandler.postDelayed(r, 2500);
   4006             } else {
   4007                 if (DEBUG_SCHEDULING) {
   4008                     Slog.i(TAG, "Full backup queue empty; not scheduling");
   4009                 }
   4010             }
   4011         }
   4012     }
   4013 
   4014     /**
   4015      * Enqueue full backup for the given app, with a note about when it last ran.
   4016      */
   4017     void enqueueFullBackup(String packageName, long lastBackedUp) {
   4018         FullBackupEntry newEntry = new FullBackupEntry(packageName, lastBackedUp);
   4019         synchronized (mQueueLock) {
   4020             int N = mFullBackupQueue.size();
   4021             // First, sanity check that we aren't adding a duplicate.  Slow but
   4022             // straightforward; we'll have at most on the order of a few hundred
   4023             // items in this list.
   4024             for (int i = N-1; i >= 0; i--) {
   4025                 final FullBackupEntry e = mFullBackupQueue.get(i);
   4026                 if (packageName.equals(e.packageName)) {
   4027                     if (DEBUG) {
   4028                         Slog.w(TAG, "Removing schedule queue dupe of " + packageName);
   4029                     }
   4030                     mFullBackupQueue.remove(i);
   4031                 }
   4032             }
   4033 
   4034             // This is also slow but easy for modest numbers of apps: work backwards
   4035             // from the end of the queue until we find an item whose last backup
   4036             // time was before this one, then insert this new entry after it.
   4037             int which;
   4038             for (which = mFullBackupQueue.size() - 1; which >= 0; which--) {
   4039                 final FullBackupEntry entry = mFullBackupQueue.get(which);
   4040                 if (entry.lastBackup <= lastBackedUp) {
   4041                     mFullBackupQueue.add(which + 1, newEntry);
   4042                     break;
   4043                 }
   4044             }
   4045             if (which < 0) {
   4046                 // this one is earlier than any existing one, so prepend
   4047                 mFullBackupQueue.add(0, newEntry);
   4048             }
   4049         }
   4050         writeFullBackupScheduleAsync();
   4051     }
   4052 
   4053     /**
   4054      * Conditions are right for a full backup operation, so run one.  The model we use is
   4055      * to perform one app backup per scheduled job execution, and to reschedule the job
   4056      * with zero latency as long as conditions remain right and we still have work to do.
   4057      *
   4058      * @return Whether ongoing work will continue.  The return value here will be passed
   4059      *         along as the return value to the scheduled job's onStartJob() callback.
   4060      */
   4061     boolean beginFullBackup(FullBackupJob scheduledJob) {
   4062         long now = System.currentTimeMillis();
   4063         FullBackupEntry entry = null;
   4064 
   4065         if (DEBUG_SCHEDULING) {
   4066             Slog.i(TAG, "Beginning scheduled full backup operation");
   4067         }
   4068 
   4069         // Great; we're able to run full backup jobs now.  See if we have any work to do.
   4070         synchronized (mQueueLock) {
   4071             if (mRunningFullBackupTask != null) {
   4072                 Slog.e(TAG, "Backup triggered but one already/still running!");
   4073                 return false;
   4074             }
   4075 
   4076             if (mFullBackupQueue.size() == 0) {
   4077                 // no work to do so just bow out
   4078                 if (DEBUG) {
   4079                     Slog.i(TAG, "Backup queue empty; doing nothing");
   4080                 }
   4081                 return false;
   4082             }
   4083 
   4084             entry = mFullBackupQueue.get(0);
   4085             long timeSinceRun = now - entry.lastBackup;
   4086             if (timeSinceRun < MIN_FULL_BACKUP_INTERVAL) {
   4087                 // It's too early to back up the next thing in the queue, so bow out
   4088                 if (MORE_DEBUG) {
   4089                     Slog.i(TAG, "Device ready but too early to back up next app");
   4090                 }
   4091                 final long latency = MIN_FULL_BACKUP_INTERVAL - timeSinceRun;
   4092                 mBackupHandler.post(new Runnable() {
   4093                     @Override public void run() {
   4094                         FullBackupJob.schedule(mContext, latency);
   4095                     }
   4096                 });
   4097                 return false;
   4098             }
   4099 
   4100             // Okay, the top thing is runnable now.  Pop it off and get going.
   4101             mFullBackupQueue.remove(0);
   4102             AtomicBoolean latch = new AtomicBoolean(false);
   4103             String[] pkg = new String[] {entry.packageName};
   4104             mRunningFullBackupTask = new PerformFullTransportBackupTask(null, pkg, true,
   4105                     scheduledJob, latch);
   4106             (new Thread(mRunningFullBackupTask)).start();
   4107         }
   4108 
   4109         return true;
   4110     }
   4111 
   4112     // The job scheduler says our constraints don't hold any more,
   4113     // so tear down any ongoing backup task right away.
   4114     void endFullBackup() {
   4115         synchronized (mQueueLock) {
   4116             if (mRunningFullBackupTask != null) {
   4117                 if (DEBUG_SCHEDULING) {
   4118                     Slog.i(TAG, "Telling running backup to stop");
   4119                 }
   4120                 mRunningFullBackupTask.setRunning(false);
   4121             }
   4122         }
   4123     }
   4124 
   4125     // ----- Restore infrastructure -----
   4126 
   4127     abstract class RestoreEngine {
   4128         static final String TAG = "RestoreEngine";
   4129 
   4130         public static final int SUCCESS = 0;
   4131         public static final int TARGET_FAILURE = -2;
   4132         public static final int TRANSPORT_FAILURE = -3;
   4133 
   4134         private AtomicBoolean mRunning = new AtomicBoolean(false);
   4135         private AtomicInteger mResult = new AtomicInteger(SUCCESS);
   4136 
   4137         public boolean isRunning() {
   4138             return mRunning.get();
   4139         }
   4140 
   4141         public void setRunning(boolean stillRunning) {
   4142             synchronized (mRunning) {
   4143                 mRunning.set(stillRunning);
   4144                 mRunning.notifyAll();
   4145             }
   4146         }
   4147 
   4148         public int waitForResult() {
   4149             synchronized (mRunning) {
   4150                 while (isRunning()) {
   4151                     try {
   4152                         mRunning.wait();
   4153                     } catch (InterruptedException e) {}
   4154                 }
   4155             }
   4156             return getResult();
   4157         }
   4158 
   4159         public int getResult() {
   4160             return mResult.get();
   4161         }
   4162 
   4163         public void setResult(int result) {
   4164             mResult.set(result);
   4165         }
   4166 
   4167         // TODO: abstract restore state and APIs
   4168     }
   4169 
   4170     // ----- Full restore from a file/socket -----
   4171 
   4172     // Description of a file in the restore datastream
   4173     static class FileMetadata {
   4174         String packageName;             // name of the owning app
   4175         String installerPackageName;    // name of the market-type app that installed the owner
   4176         int type;                       // e.g. BackupAgent.TYPE_DIRECTORY
   4177         String domain;                  // e.g. FullBackup.DATABASE_TREE_TOKEN
   4178         String path;                    // subpath within the semantic domain
   4179         long mode;                      // e.g. 0666 (actually int)
   4180         long mtime;                     // last mod time, UTC time_t (actually int)
   4181         long size;                      // bytes of content
   4182 
   4183         @Override
   4184         public String toString() {
   4185             StringBuilder sb = new StringBuilder(128);
   4186             sb.append("FileMetadata{");
   4187             sb.append(packageName); sb.append(',');
   4188             sb.append(type); sb.append(',');
   4189             sb.append(domain); sb.append(':'); sb.append(path); sb.append(',');
   4190             sb.append(size);
   4191             sb.append('}');
   4192             return sb.toString();
   4193         }
   4194     }
   4195 
   4196     enum RestorePolicy {
   4197         IGNORE,
   4198         ACCEPT,
   4199         ACCEPT_IF_APK
   4200     }
   4201 
   4202     // Full restore engine, used by both adb restore and transport-based full restore
   4203     class FullRestoreEngine extends RestoreEngine {
   4204         // Dedicated observer, if any
   4205         IFullBackupRestoreObserver mObserver;
   4206 
   4207         // Where we're delivering the file data as we go
   4208         IBackupAgent mAgent;
   4209 
   4210         // Are we permitted to only deliver a specific package's metadata?
   4211         PackageInfo mOnlyPackage;
   4212 
   4213         boolean mAllowApks;
   4214         boolean mAllowObbs;
   4215 
   4216         // Which package are we currently handling data for?
   4217         String mAgentPackage;
   4218 
   4219         // Info for working with the target app process
   4220         ApplicationInfo mTargetApp;
   4221 
   4222         // Machinery for restoring OBBs
   4223         FullBackupObbConnection mObbConnection = null;
   4224 
   4225         // possible handling states for a given package in the restore dataset
   4226         final HashMap<String, RestorePolicy> mPackagePolicies
   4227                 = new HashMap<String, RestorePolicy>();
   4228 
   4229         // installer package names for each encountered app, derived from the manifests
   4230         final HashMap<String, String> mPackageInstallers = new HashMap<String, String>();
   4231 
   4232         // Signatures for a given package found in its manifest file
   4233         final HashMap<String, Signature[]> mManifestSignatures
   4234                 = new HashMap<String, Signature[]>();
   4235 
   4236         // Packages we've already wiped data on when restoring their first file
   4237         final HashSet<String> mClearedPackages = new HashSet<String>();
   4238 
   4239         // How much data have we moved?
   4240         long mBytes;
   4241 
   4242         // Working buffer
   4243         byte[] mBuffer;
   4244 
   4245         // Pipes for moving data
   4246         ParcelFileDescriptor[] mPipes = null;
   4247 
   4248         // Widget blob to be restored out-of-band
   4249         byte[] mWidgetData = null;
   4250 
   4251         // Runner that can be placed in a separate thread to do in-process
   4252         // invocations of the full restore API asynchronously
   4253         class RestoreFileRunnable implements Runnable {
   4254             IBackupAgent mAgent;
   4255             FileMetadata mInfo;
   4256             ParcelFileDescriptor mSocket;
   4257             int mToken;
   4258 
   4259             RestoreFileRunnable(IBackupAgent agent, FileMetadata info,
   4260                     ParcelFileDescriptor socket, int token) throws IOException {
   4261                 mAgent = agent;
   4262                 mInfo = info;
   4263                 mToken = token;
   4264 
   4265                 // This class is used strictly for process-local binder invocations.  The
   4266                 // semantics of ParcelFileDescriptor differ in this case; in particular, we
   4267                 // do not automatically get a 'dup'ed descriptor that we can can continue
   4268                 // to use asynchronously from the caller.  So, we make sure to dup it ourselves
   4269                 // before proceeding to do the restore.
   4270                 mSocket = ParcelFileDescriptor.dup(socket.getFileDescriptor());
   4271             }
   4272 
   4273             @Override
   4274             public void run() {
   4275                 try {
   4276                     mAgent.doRestoreFile(mSocket, mInfo.size, mInfo.type,
   4277                             mInfo.domain, mInfo.path, mInfo.mode, mInfo.mtime,
   4278                             mToken, mBackupManagerBinder);
   4279                 } catch (RemoteException e) {
   4280                     // never happens; this is used strictly for local binder calls
   4281                 }
   4282             }
   4283         }
   4284 
   4285         public FullRestoreEngine(IFullBackupRestoreObserver observer, PackageInfo onlyPackage,
   4286                 boolean allowApks, boolean allowObbs) {
   4287             mObserver = observer;
   4288             mOnlyPackage = onlyPackage;
   4289             mAllowApks = allowApks;
   4290             mAllowObbs = allowObbs;
   4291             mBuffer = new byte[32 * 1024];
   4292             mBytes = 0;
   4293         }
   4294 
   4295         public boolean restoreOneFile(InputStream instream) {
   4296             if (!isRunning()) {
   4297                 Slog.w(TAG, "Restore engine used after halting");
   4298                 return false;
   4299             }
   4300 
   4301             FileMetadata info;
   4302             try {
   4303                 if (MORE_DEBUG) {
   4304                     Slog.v(TAG, "Reading tar header for restoring file");
   4305                 }
   4306                 info = readTarHeaders(instream);
   4307                 if (info != null) {
   4308                     if (MORE_DEBUG) {
   4309                         dumpFileMetadata(info);
   4310                     }
   4311 
   4312                     final String pkg = info.packageName;
   4313                     if (!pkg.equals(mAgentPackage)) {
   4314                         // In the single-package case, it's a semantic error to expect
   4315                         // one app's data but see a different app's on the wire
   4316                         if (mOnlyPackage != null) {
   4317                             if (!pkg.equals(mOnlyPackage.packageName)) {
   4318                                 Slog.w(TAG, "Expected data for " + mOnlyPackage
   4319                                         + " but saw " + pkg);
   4320                                 setResult(RestoreEngine.TRANSPORT_FAILURE);
   4321                                 setRunning(false);
   4322                                 return false;
   4323                             }
   4324                         }
   4325 
   4326                         // okay, change in package; set up our various
   4327                         // bookkeeping if we haven't seen it yet
   4328                         if (!mPackagePolicies.containsKey(pkg)) {
   4329                             mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
   4330                         }
   4331 
   4332                         // Clean up the previous agent relationship if necessary,
   4333                         // and let the observer know we're considering a new app.
   4334                         if (mAgent != null) {
   4335                             if (DEBUG) Slog.d(TAG, "Saw new package; finalizing old one");
   4336                             // Now we're really done
   4337                             tearDownPipes();
   4338                             tearDownAgent(mTargetApp);
   4339                             mTargetApp = null;
   4340                             mAgentPackage = null;
   4341                         }
   4342                     }
   4343 
   4344                     if (info.path.equals(BACKUP_MANIFEST_FILENAME)) {
   4345                         mPackagePolicies.put(pkg, readAppManifest(info, instream));
   4346                         mPackageInstallers.put(pkg, info.installerPackageName);
   4347                         // We've read only the manifest content itself at this point,
   4348                         // so consume the footer before looping around to the next
   4349                         // input file
   4350                         skipTarPadding(info.size, instream);
   4351                         sendOnRestorePackage(pkg);
   4352                     } else if (info.path.equals(BACKUP_METADATA_FILENAME)) {
   4353                         // Metadata blobs!
   4354                         readMetadata(info, instream);
   4355                         skipTarPadding(info.size, instream);
   4356                     } else {
   4357                         // Non-manifest, so it's actual file data.  Is this a package
   4358                         // we're ignoring?
   4359                         boolean okay = true;
   4360                         RestorePolicy policy = mPackagePolicies.get(pkg);
   4361                         switch (policy) {
   4362                             case IGNORE:
   4363                                 okay = false;
   4364                                 break;
   4365 
   4366                             case ACCEPT_IF_APK:
   4367                                 // If we're in accept-if-apk state, then the first file we
   4368                                 // see MUST be the apk.
   4369                                 if (info.domain.equals(FullBackup.APK_TREE_TOKEN)) {
   4370                                     if (DEBUG) Slog.d(TAG, "APK file; installing");
   4371                                     // Try to install the app.
   4372                                     String installerName = mPackageInstallers.get(pkg);
   4373                                     okay = installApk(info, installerName, instream);
   4374                                     // good to go; promote to ACCEPT
   4375                                     mPackagePolicies.put(pkg, (okay)
   4376                                             ? RestorePolicy.ACCEPT
   4377                                                     : RestorePolicy.IGNORE);
   4378                                     // At this point we've consumed this file entry
   4379                                     // ourselves, so just strip the tar footer and
   4380                                     // go on to the next file in the input stream
   4381                                     skipTarPadding(info.size, instream);
   4382                                     return true;
   4383                                 } else {
   4384                                     // File data before (or without) the apk.  We can't
   4385                                     // handle it coherently in this case so ignore it.
   4386                                     mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
   4387                                     okay = false;
   4388                                 }
   4389                                 break;
   4390 
   4391                             case ACCEPT:
   4392                                 if (info.domain.equals(FullBackup.APK_TREE_TOKEN)) {
   4393                                     if (DEBUG) Slog.d(TAG, "apk present but ACCEPT");
   4394                                     // we can take the data without the apk, so we
   4395                                     // *want* to do so.  skip the apk by declaring this
   4396                                     // one file not-okay without changing the restore
   4397                                     // policy for the package.
   4398                                     okay = false;
   4399                                 }
   4400                                 break;
   4401 
   4402                             default:
   4403                                 // Something has gone dreadfully wrong when determining
   4404                                 // the restore policy from the manifest.  Ignore the
   4405                                 // rest of this package's data.
   4406                                 Slog.e(TAG, "Invalid policy from manifest");
   4407                                 okay = false;
   4408                                 mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
   4409                                 break;
   4410                         }
   4411 
   4412                         // Is it a *file* we need to drop?
   4413                         if (!isRestorableFile(info)) {
   4414                             okay = false;
   4415                         }
   4416 
   4417                         // If the policy is satisfied, go ahead and set up to pipe the
   4418                         // data to the agent.
   4419                         if (DEBUG && okay && mAgent != null) {
   4420                             Slog.i(TAG, "Reusing existing agent instance");
   4421                         }
   4422                         if (okay && mAgent == null) {
   4423                             if (DEBUG) Slog.d(TAG, "Need to launch agent for " + pkg);
   4424 
   4425                             try {
   4426                                 mTargetApp = mPackageManager.getApplicationInfo(pkg, 0);
   4427 
   4428                                 // If we haven't sent any data to this app yet, we probably
   4429                                 // need to clear it first.  Check that.
   4430                                 if (!mClearedPackages.contains(pkg)) {
   4431                                     // apps with their own backup agents are
   4432                                     // responsible for coherently managing a full
   4433                                     // restore.
   4434                                     if (mTargetApp.backupAgentName == null) {
   4435                                         if (DEBUG) Slog.d(TAG, "Clearing app data preparatory to full restore");
   4436                                         clearApplicationDataSynchronous(pkg);
   4437                                     } else {
   4438                                         if (DEBUG) Slog.d(TAG, "backup agent ("
   4439                                                 + mTargetApp.backupAgentName + ") => no clear");
   4440                                     }
   4441                                     mClearedPackages.add(pkg);
   4442                                 } else {
   4443                                     if (DEBUG) Slog.d(TAG, "We've initialized this app already; no clear required");
   4444                                 }
   4445 
   4446                                 // All set; now set up the IPC and launch the agent
   4447                                 setUpPipes();
   4448                                 mAgent = bindToAgentSynchronous(mTargetApp,
   4449                                         IApplicationThread.BACKUP_MODE_RESTORE_FULL);
   4450                                 mAgentPackage = pkg;
   4451                             } catch (IOException e) {
   4452                                 // fall through to error handling
   4453                             } catch (NameNotFoundException e) {
   4454                                 // fall through to error handling
   4455                             }
   4456 
   4457                             if (mAgent == null) {
   4458                                 if (DEBUG) Slog.d(TAG, "Unable to create agent for " + pkg);
   4459                                 okay = false;
   4460                                 tearDownPipes();
   4461                                 mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
   4462                             }
   4463                         }
   4464 
   4465                         // Sanity check: make sure we never give data to the wrong app.  This
   4466                         // should never happen but a little paranoia here won't go amiss.
   4467                         if (okay && !pkg.equals(mAgentPackage)) {
   4468                             Slog.e(TAG, "Restoring data for " + pkg
   4469                                     + " but agent is for " + mAgentPackage);
   4470                             okay = false;
   4471                         }
   4472 
   4473                         // At this point we have an agent ready to handle the full
   4474                         // restore data as well as a pipe for sending data to
   4475                         // that agent.  Tell the agent to start reading from the
   4476                         // pipe.
   4477                         if (okay) {
   4478                             boolean agentSuccess = true;
   4479                             long toCopy = info.size;
   4480                             final int token = generateToken();
   4481                             try {
   4482                                 prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL, null);
   4483                                 if (info.domain.equals(FullBackup.OBB_TREE_TOKEN)) {
   4484                                     if (DEBUG) Slog.d(TAG, "Restoring OBB file for " + pkg
   4485                                             + " : " + info.path);
   4486                                     mObbConnection.restoreObbFile(pkg, mPipes[0],
   4487                                             info.size, info.type, info.path, info.mode,
   4488                                             info.mtime, token, mBackupManagerBinder);
   4489                                 } else {
   4490                                     if (DEBUG) Slog.d(TAG, "Invoking agent to restore file "
   4491                                             + info.path);
   4492                                     // fire up the app's agent listening on the socket.  If
   4493                                     // the agent is running in the system process we can't
   4494                                     // just invoke it asynchronously, so we provide a thread
   4495                                     // for it here.
   4496                                     if (mTargetApp.processName.equals("system")) {
   4497                                         Slog.d(TAG, "system process agent - spinning a thread");
   4498                                         RestoreFileRunnable runner = new RestoreFileRunnable(
   4499                                                 mAgent, info, mPipes[0], token);
   4500                                         new Thread(runner, "restore-sys-runner").start();
   4501                                     } else {
   4502                                         mAgent.doRestoreFile(mPipes[0], info.size, info.type,
   4503                                                 info.domain, info.path, info.mode, info.mtime,
   4504                                                 token, mBackupManagerBinder);
   4505                                     }
   4506                                 }
   4507                             } catch (IOException e) {
   4508                                 // couldn't dup the socket for a process-local restore
   4509                                 Slog.d(TAG, "Couldn't establish restore");
   4510                                 agentSuccess = false;
   4511                                 okay = false;
   4512                             } catch (RemoteException e) {
   4513                                 // whoops, remote entity went away.  We'll eat the content
   4514                                 // ourselves, then, and not copy it over.
   4515                                 Slog.e(TAG, "Agent crashed during full restore");
   4516                                 agentSuccess = false;
   4517                                 okay = false;
   4518                             }
   4519 
   4520                             // Copy over the data if the agent is still good
   4521                             if (okay) {
   4522                                 if (MORE_DEBUG) {
   4523                                     Slog.v(TAG, "  copying to restore agent: "
   4524                                             + toCopy + " bytes");
   4525                                 }
   4526                                 boolean pipeOkay = true;
   4527                                 FileOutputStream pipe = new FileOutputStream(
   4528                                         mPipes[1].getFileDescriptor());
   4529                                 while (toCopy > 0) {
   4530                                     int toRead = (toCopy > mBuffer.length)
   4531                                             ? mBuffer.length : (int)toCopy;
   4532                                     int nRead = instream.read(mBuffer, 0, toRead);
   4533                                     if (nRead >= 0) mBytes += nRead;
   4534                                     if (nRead <= 0) break;
   4535                                     toCopy -= nRead;
   4536 
   4537                                     // send it to the output pipe as long as things
   4538                                     // are still good
   4539                                     if (pipeOkay) {
   4540                                         try {
   4541                                             pipe.write(mBuffer, 0, nRead);
   4542                                         } catch (IOException e) {
   4543                                             Slog.e(TAG, "Failed to write to restore pipe", e);
   4544                                             pipeOkay = false;
   4545                                         }
   4546                                     }
   4547                                 }
   4548 
   4549                                 // done sending that file!  Now we just need to consume
   4550                                 // the delta from info.size to the end of block.
   4551                                 skipTarPadding(info.size, instream);
   4552 
   4553                                 // and now that we've sent it all, wait for the remote
   4554                                 // side to acknowledge receipt
   4555                                 agentSuccess = waitUntilOperationComplete(token);
   4556                             }
   4557 
   4558                             // okay, if the remote end failed at any point, deal with
   4559                             // it by ignoring the rest of the restore on it
   4560                             if (!agentSuccess) {
   4561                                 if (DEBUG) {
   4562                                     Slog.i(TAG, "Agent failure; ending restore");
   4563                                 }
   4564                                 mBackupHandler.removeMessages(MSG_TIMEOUT);
   4565                                 tearDownPipes();
   4566                                 tearDownAgent(mTargetApp);
   4567                                 mAgent = null;
   4568                                 mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
   4569 
   4570                                 // If this was a single-package restore, we halt immediately
   4571                                 // with an agent error under these circumstances
   4572                                 if (mOnlyPackage != null) {
   4573                                     setResult(RestoreEngine.TARGET_FAILURE);
   4574                                     setRunning(false);
   4575                                     return false;
   4576                                 }
   4577                             }
   4578                         }
   4579 
   4580                         // Problems setting up the agent communication, an explicitly
   4581                         // dropped file, or an already-ignored package: skip to the
   4582                         // next stream entry by reading and discarding this file.
   4583                         if (!okay) {
   4584                             if (DEBUG) Slog.d(TAG, "[discarding file content]");
   4585                             long bytesToConsume = (info.size + 511) & ~511;
   4586                             while (bytesToConsume > 0) {
   4587                                 int toRead = (bytesToConsume > mBuffer.length)
   4588                                         ? mBuffer.length : (int)bytesToConsume;
   4589                                 long nRead = instream.read(mBuffer, 0, toRead);
   4590                                 if (nRead >= 0) mBytes += nRead;
   4591                                 if (nRead <= 0) break;
   4592                                 bytesToConsume -= nRead;
   4593                             }
   4594                         }
   4595                     }
   4596                 }
   4597             } catch (IOException e) {
   4598                 if (DEBUG) Slog.w(TAG, "io exception on restore socket read", e);
   4599                 setResult(RestoreEngine.TRANSPORT_FAILURE);
   4600                 info = null;
   4601             }
   4602 
   4603             // If we got here we're either running smoothly or we've finished
   4604             if (info == null) {
   4605                 if (MORE_DEBUG) {
   4606                     Slog.i(TAG, "No [more] data for this package; tearing down");
   4607                 }
   4608                 tearDownPipes();
   4609                 tearDownAgent(mTargetApp);
   4610                 setRunning(false);
   4611             }
   4612             return (info != null);
   4613         }
   4614 
   4615         void setUpPipes() throws IOException {
   4616             mPipes = ParcelFileDescriptor.createPipe();
   4617         }
   4618 
   4619         void tearDownPipes() {
   4620             if (mPipes != null) {
   4621                 try {
   4622                     mPipes[0].close();
   4623                     mPipes[0] = null;
   4624                     mPipes[1].close();
   4625                     mPipes[1] = null;
   4626                 } catch (IOException e) {
   4627                     Slog.w(TAG, "Couldn't close agent pipes", e);
   4628                 }
   4629                 mPipes = null;
   4630             }
   4631         }
   4632 
   4633         void tearDownAgent(ApplicationInfo app) {
   4634             if (mAgent != null) {
   4635                 try {
   4636                     // unbind and tidy up even on timeout or failure, just in case
   4637                     mActivityManager.unbindBackupAgent(app);
   4638 
   4639                     // The agent was running with a stub Application object, so shut it down.
   4640                     // !!! We hardcode the confirmation UI's package name here rather than use a
   4641                     //     manifest flag!  TODO something less direct.
   4642                     if (app.uid != Process.SYSTEM_UID
   4643                             && !app.packageName.equals("com.android.backupconfirm")) {
   4644                         if (DEBUG) Slog.d(TAG, "Killing host process");
   4645                         mActivityManager.killApplicationProcess(app.processName, app.uid);
   4646                     } else {
   4647                         if (DEBUG) Slog.d(TAG, "Not killing after full restore");
   4648                     }
   4649                 } catch (RemoteException e) {
   4650                     Slog.d(TAG, "Lost app trying to shut down");
   4651                 }
   4652                 mAgent = null;
   4653             }
   4654         }
   4655 
   4656         class RestoreInstallObserver extends IPackageInstallObserver.Stub {
   4657             final AtomicBoolean mDone = new AtomicBoolean();
   4658             String mPackageName;
   4659             int mResult;
   4660 
   4661             public void reset() {
   4662                 synchronized (mDone) {
   4663                     mDone.set(false);
   4664                 }
   4665             }
   4666 
   4667             public void waitForCompletion() {
   4668                 synchronized (mDone) {
   4669                     while (mDone.get() == false) {
   4670                         try {
   4671                             mDone.wait();
   4672                         } catch (InterruptedException e) { }
   4673                     }
   4674                 }
   4675             }
   4676 
   4677             int getResult() {
   4678                 return mResult;
   4679             }
   4680 
   4681             @Override
   4682             public void packageInstalled(String packageName, int returnCode)
   4683                     throws RemoteException {
   4684                 synchronized (mDone) {
   4685                     mResult = returnCode;
   4686                     mPackageName = packageName;
   4687                     mDone.set(true);
   4688                     mDone.notifyAll();
   4689                 }
   4690             }
   4691         }
   4692 
   4693         class RestoreDeleteObserver extends IPackageDeleteObserver.Stub {
   4694             final AtomicBoolean mDone = new AtomicBoolean();
   4695             int mResult;
   4696 
   4697             public void reset() {
   4698                 synchronized (mDone) {
   4699                     mDone.set(false);
   4700                 }
   4701             }
   4702 
   4703             public void waitForCompletion() {
   4704                 synchronized (mDone) {
   4705                     while (mDone.get() == false) {
   4706                         try {
   4707                             mDone.wait();
   4708                         } catch (InterruptedException e) { }
   4709                     }
   4710                 }
   4711             }
   4712 
   4713             @Override
   4714             public void packageDeleted(String packageName, int returnCode) throws RemoteException {
   4715                 synchronized (mDone) {
   4716                     mResult = returnCode;
   4717                     mDone.set(true);
   4718                     mDone.notifyAll();
   4719                 }
   4720             }
   4721         }
   4722 
   4723         final RestoreInstallObserver mInstallObserver = new RestoreInstallObserver();
   4724         final RestoreDeleteObserver mDeleteObserver = new RestoreDeleteObserver();
   4725 
   4726         boolean installApk(FileMetadata info, String installerPackage, InputStream instream) {
   4727             boolean okay = true;
   4728 
   4729             if (DEBUG) Slog.d(TAG, "Installing from backup: " + info.packageName);
   4730 
   4731             // The file content is an .apk file.  Copy it out to a staging location and
   4732             // attempt to install it.
   4733             File apkFile = new File(mDataDir, info.packageName);
   4734             try {
   4735                 FileOutputStream apkStream = new FileOutputStream(apkFile);
   4736                 byte[] buffer = new byte[32 * 1024];
   4737                 long size = info.size;
   4738                 while (size > 0) {
   4739                     long toRead = (buffer.length < size) ? buffer.length : size;
   4740                     int didRead = instream.read(buffer, 0, (int)toRead);
   4741                     if (didRead >= 0) mBytes += didRead;
   4742                     apkStream.write(buffer, 0, didRead);
   4743                     size -= didRead;
   4744                 }
   4745                 apkStream.close();
   4746 
   4747                 // make sure the installer can read it
   4748                 apkFile.setReadable(true, false);
   4749 
   4750                 // Now install it
   4751                 Uri packageUri = Uri.fromFile(apkFile);
   4752                 mInstallObserver.reset();
   4753                 mPackageManager.installPackage(packageUri, mInstallObserver,
   4754                         PackageManager.INSTALL_REPLACE_EXISTING | PackageManager.INSTALL_FROM_ADB,
   4755                         installerPackage);
   4756                 mInstallObserver.waitForCompletion();
   4757 
   4758                 if (mInstallObserver.getResult() != PackageManager.INSTALL_SUCCEEDED) {
   4759                     // The only time we continue to accept install of data even if the
   4760                     // apk install failed is if we had already determined that we could
   4761                     // accept the data regardless.
   4762                     if (mPackagePolicies.get(info.packageName) != RestorePolicy.ACCEPT) {
   4763                         okay = false;
   4764                     }
   4765                 } else {
   4766                     // Okay, the install succeeded.  Make sure it was the right app.
   4767                     boolean uninstall = false;
   4768                     if (!mInstallObserver.mPackageName.equals(info.packageName)) {
   4769                         Slog.w(TAG, "Restore stream claimed to include apk for "
   4770                                 + info.packageName + " but apk was really "
   4771                                 + mInstallObserver.mPackageName);
   4772                         // delete the package we just put in place; it might be fraudulent
   4773                         okay = false;
   4774                         uninstall = true;
   4775                     } else {
   4776                         try {
   4777                             PackageInfo pkg = mPackageManager.getPackageInfo(info.packageName,
   4778                                     PackageManager.GET_SIGNATURES);
   4779                             if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) {
   4780                                 Slog.w(TAG, "Restore stream contains apk of package "
   4781                                         + info.packageName + " but it disallows backup/restore");
   4782                                 okay = false;
   4783                             } else {
   4784                                 // So far so good -- do the signatures match the manifest?
   4785                                 Signature[] sigs = mManifestSignatures.get(info.packageName);
   4786                                 if (signaturesMatch(sigs, pkg)) {
   4787                                     // If this is a system-uid app without a declared backup agent,
   4788                                     // don't restore any of the file data.
   4789                                     if ((pkg.applicationInfo.uid < Process.FIRST_APPLICATION_UID)
   4790                                             && (pkg.applicationInfo.backupAgentName == null)) {
   4791                                         Slog.w(TAG, "Installed app " + info.packageName
   4792                                                 + " has restricted uid and no agent");
   4793                                         okay = false;
   4794                                     }
   4795                                 } else {
   4796                                     Slog.w(TAG, "Installed app " + info.packageName
   4797                                             + " signatures do not match restore manifest");
   4798                                     okay = false;
   4799                                     uninstall = true;
   4800                                 }
   4801                             }
   4802                         } catch (NameNotFoundException e) {
   4803                             Slog.w(TAG, "Install of package " + info.packageName
   4804                                     + " succeeded but now not found");
   4805                             okay = false;
   4806                         }
   4807                     }
   4808 
   4809                     // If we're not okay at this point, we need to delete the package
   4810                     // that we just installed.
   4811                     if (uninstall) {
   4812                         mDeleteObserver.reset();
   4813                         mPackageManager.deletePackage(mInstallObserver.mPackageName,
   4814                                 mDeleteObserver, 0);
   4815                         mDeleteObserver.waitForCompletion();
   4816                     }
   4817                 }
   4818             } catch (IOException e) {
   4819                 Slog.e(TAG, "Unable to transcribe restored apk for install");
   4820                 okay = false;
   4821             } finally {
   4822                 apkFile.delete();
   4823             }
   4824 
   4825             return okay;
   4826         }
   4827 
   4828         // Given an actual file content size, consume the post-content padding mandated
   4829         // by the tar format.
   4830         void skipTarPadding(long size, InputStream instream) throws IOException {
   4831             long partial = (size + 512) % 512;
   4832             if (partial > 0) {
   4833                 final int needed = 512 - (int)partial;
   4834                 if (MORE_DEBUG) {
   4835                     Slog.i(TAG, "Skipping tar padding: " + needed + " bytes");
   4836                 }
   4837                 byte[] buffer = new byte[needed];
   4838                 if (readExactly(instream, buffer, 0, needed) == needed) {
   4839                     mBytes += needed;
   4840                 } else throw new IOException("Unexpected EOF in padding");
   4841             }
   4842         }
   4843 
   4844         // Read a widget metadata file, returning the restored blob
   4845         void readMetadata(FileMetadata info, InputStream instream) throws IOException {
   4846             // Fail on suspiciously large widget dump files
   4847             if (info.size > 64 * 1024) {
   4848                 throw new IOException("Metadata too big; corrupt? size=" + info.size);
   4849             }
   4850 
   4851             byte[] buffer = new byte[(int) info.size];
   4852             if (readExactly(instream, buffer, 0, (int)info.size) == info.size) {
   4853                 mBytes += info.size;
   4854             } else throw new IOException("Unexpected EOF in widget data");
   4855 
   4856             String[] str = new String[1];
   4857             int offset = extractLine(buffer, 0, str);
   4858             int version = Integer.parseInt(str[0]);
   4859             if (version == BACKUP_MANIFEST_VERSION) {
   4860                 offset = extractLine(buffer, offset, str);
   4861                 final String pkg = str[0];
   4862                 if (info.packageName.equals(pkg)) {
   4863                     // Data checks out -- the rest of the buffer is a concatenation of
   4864                     // binary blobs as described in the comment at writeAppWidgetData()
   4865                     ByteArrayInputStream bin = new ByteArrayInputStream(buffer,
   4866                             offset, buffer.length - offset);
   4867                     DataInputStream in = new DataInputStream(bin);
   4868                     while (bin.available() > 0) {
   4869                         int token = in.readInt();
   4870                         int size = in.readInt();
   4871                         if (size > 64 * 1024) {
   4872                             throw new IOException("Datum "
   4873                                     + Integer.toHexString(token)
   4874                                     + " too big; corrupt? size=" + info.size);
   4875                         }
   4876                         switch (token) {
   4877                             case BACKUP_WIDGET_METADATA_TOKEN:
   4878                             {
   4879                                 if (MORE_DEBUG) {
   4880                                     Slog.i(TAG, "Got widget metadata for " + info.packageName);
   4881                                 }
   4882                                 mWidgetData = new byte[size];
   4883                                 in.read(mWidgetData);
   4884                                 break;
   4885                             }
   4886                             default:
   4887                             {
   4888                                 if (DEBUG) {
   4889                                     Slog.i(TAG, "Ignoring metadata blob "
   4890                                             + Integer.toHexString(token)
   4891                                             + " for " + info.packageName);
   4892                                 }
   4893                                 in.skipBytes(size);
   4894                                 break;
   4895                             }
   4896                         }
   4897                     }
   4898                 } else {
   4899                     Slog.w(TAG, "Metadata mismatch: package " + info.packageName
   4900                             + " but widget data for " + pkg);
   4901                 }
   4902             } else {
   4903                 Slog.w(TAG, "Unsupported metadata version " + version);
   4904             }
   4905         }
   4906 
   4907         // Returns a policy constant
   4908         RestorePolicy readAppManifest(FileMetadata info, InputStream instream)
   4909                 throws IOException {
   4910             // Fail on suspiciously large manifest files
   4911             if (info.size > 64 * 1024) {
   4912                 throw new IOException("Restore manifest too big; corrupt? size=" + info.size);
   4913             }
   4914 
   4915             byte[] buffer = new byte[(int) info.size];
   4916             if (MORE_DEBUG) {
   4917                 Slog.i(TAG, "   readAppManifest() looking for " + info.size + " bytes, "
   4918                         + mBytes + " already consumed");
   4919             }
   4920             if (readExactly(instream, buffer, 0, (int)info.size) == info.size) {
   4921                 mBytes += info.size;
   4922             } else throw new IOException("Unexpected EOF in manifest");
   4923 
   4924             RestorePolicy policy = RestorePolicy.IGNORE;
   4925             String[] str = new String[1];
   4926             int offset = 0;
   4927 
   4928             try {
   4929                 offset = extractLine(buffer, offset, str);
   4930                 int version = Integer.parseInt(str[0]);
   4931                 if (version == BACKUP_MANIFEST_VERSION) {
   4932                     offset = extractLine(buffer, offset, str);
   4933                     String manifestPackage = str[0];
   4934                     // TODO: handle <original-package>
   4935                     if (manifestPackage.equals(info.packageName)) {
   4936                         offset = extractLine(buffer, offset, str);
   4937                         version = Integer.parseInt(str[0]);  // app version
   4938                         offset = extractLine(buffer, offset, str);
   4939                         int platformVersion = Integer.parseInt(str[0]);
   4940                         offset = extractLine(buffer, offset, str);
   4941                         info.installerPackageName = (str[0].length() > 0) ? str[0] : null;
   4942                         offset = extractLine(buffer, offset, str);
   4943                         boolean hasApk = str[0].equals("1");
   4944                         offset = extractLine(buffer, offset, str);
   4945                         int numSigs = Integer.parseInt(str[0]);
   4946                         if (numSigs > 0) {
   4947                             Signature[] sigs = new Signature[numSigs];
   4948                             for (int i = 0; i < numSigs; i++) {
   4949                                 offset = extractLine(buffer, offset, str);
   4950                                 sigs[i] = new Signature(str[0]);
   4951                             }
   4952                             mManifestSignatures.put(info.packageName, sigs);
   4953 
   4954                             // Okay, got the manifest info we need...
   4955                             try {
   4956                                 PackageInfo pkgInfo = mPackageManager.getPackageInfo(
   4957                                         info.packageName, PackageManager.GET_SIGNATURES);
   4958                                 // Fall through to IGNORE if the app explicitly disallows backup
   4959                                 final int flags = pkgInfo.applicationInfo.flags;
   4960                                 if ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0) {
   4961                                     // Restore system-uid-space packages only if they have
   4962                                     // defined a custom backup agent
   4963                                     if ((pkgInfo.applicationInfo.uid >= Process.FIRST_APPLICATION_UID)
   4964                                             || (pkgInfo.applicationInfo.backupAgentName != null)) {
   4965                                         // Verify signatures against any installed version; if they
   4966                                         // don't match, then we fall though and ignore the data.  The
   4967                                         // signatureMatch() method explicitly ignores the signature
   4968                                         // check for packages installed on the system partition, because
   4969                                         // such packages are signed with the platform cert instead of
   4970                                         // the app developer's cert, so they're different on every
   4971                                         // device.
   4972                                         if (signaturesMatch(sigs, pkgInfo)) {
   4973                                             if (pkgInfo.versionCode >= version) {
   4974                                                 Slog.i(TAG, "Sig + version match; taking data");
   4975                                                 policy = RestorePolicy.ACCEPT;
   4976                                             } else {
   4977                                                 // The data is from a newer version of the app than
   4978                                                 // is presently installed.  That means we can only
   4979                                                 // use it if the matching apk is also supplied.
   4980                                                 if (mAllowApks) {
   4981                                                     Slog.i(TAG, "Data version " + version
   4982                                                             + " is newer than installed version "
   4983                                                             + pkgInfo.versionCode
   4984                                                             + " - requiring apk");
   4985                                                     policy = RestorePolicy.ACCEPT_IF_APK;
   4986                                                 } else {
   4987                                                     Slog.i(TAG, "Data requires newer version "
   4988                                                             + version + "; ignoring");
   4989                                                     policy = RestorePolicy.IGNORE;
   4990                                                 }
   4991                                             }
   4992                                         } else {
   4993                                             Slog.w(TAG, "Restore manifest signatures do not match "
   4994                                                     + "installed application for " + info.packageName);
   4995                                         }
   4996                                     } else {
   4997                                         Slog.w(TAG, "Package " + info.packageName
   4998                                                 + " is system level with no agent");
   4999                                     }
   5000                                 } else {
   5001                                     if (DEBUG) Slog.i(TAG, "Restore manifest from "
   5002                                             + info.packageName + " but allowBackup=false");
   5003                                 }
   5004                             } catch (NameNotFoundException e) {
   5005                                 // Okay, the target app isn't installed.  We can process
   5006                                 // the restore properly only if the dataset provides the
   5007                                 // apk file and we can successfully install it.
   5008                                 if (mAllowApks) {
   5009                                     if (DEBUG) Slog.i(TAG, "Package " + info.packageName
   5010                                             + " not installed; requiring apk in dataset");
   5011                                     policy = RestorePolicy.ACCEPT_IF_APK;
   5012                                 } else {
   5013                                     policy = RestorePolicy.IGNORE;
   5014                                 }
   5015                             }
   5016 
   5017                             if (policy == RestorePolicy.ACCEPT_IF_APK && !hasApk) {
   5018                                 Slog.i(TAG, "Cannot restore package " + info.packageName
   5019                                         + " without the matching .apk");
   5020                             }
   5021                         } else {
   5022                             Slog.i(TAG, "Missing signature on backed-up package "
   5023                                     + info.packageName);
   5024                         }
   5025                     } else {
   5026                         Slog.i(TAG, "Expected package " + info.packageName
   5027                                 + " but restore manifest claims " + manifestPackage);
   5028                     }
   5029                 } else {
   5030                     Slog.i(TAG, "Unknown restore manifest version " + version
   5031                             + " for package " + info.packageName);
   5032                 }
   5033             } catch (NumberFormatException e) {
   5034                 Slog.w(TAG, "Corrupt restore manifest for package " + info.packageName);
   5035             } catch (IllegalArgumentException e) {
   5036                 Slog.w(TAG, e.getMessage());
   5037             }
   5038 
   5039             return policy;
   5040         }
   5041 
   5042         // Builds a line from a byte buffer starting at 'offset', and returns
   5043         // the index of the next unconsumed data in the buffer.
   5044         int extractLine(byte[] buffer, int offset, String[] outStr) throws IOException {
   5045             final int end = buffer.length;
   5046             if (offset >= end) throw new IOException("Incomplete data");
   5047 
   5048             int pos;
   5049             for (pos = offset; pos < end; pos++) {
   5050                 byte c = buffer[pos];
   5051                 // at LF we declare end of line, and return the next char as the
   5052                 // starting point for the next time through
   5053                 if (c == '\n') {
   5054                     break;
   5055                 }
   5056             }
   5057             outStr[0] = new String(buffer, offset, pos - offset);
   5058             pos++;  // may be pointing an extra byte past the end but that's okay
   5059             return pos;
   5060         }
   5061 
   5062         void dumpFileMetadata(FileMetadata info) {
   5063             if (DEBUG) {
   5064                 StringBuilder b = new StringBuilder(128);
   5065 
   5066                 // mode string
   5067                 b.append((info.type == BackupAgent.TYPE_DIRECTORY) ? 'd' : '-');
   5068                 b.append(((info.mode & 0400) != 0) ? 'r' : '-');
   5069                 b.append(((info.mode & 0200) != 0) ? 'w' : '-');
   5070                 b.append(((info.mode & 0100) != 0) ? 'x' : '-');
   5071                 b.append(((info.mode & 0040) != 0) ? 'r' : '-');
   5072                 b.append(((info.mode & 0020) != 0) ? 'w' : '-');
   5073                 b.append(((info.mode & 0010) != 0) ? 'x' : '-');
   5074                 b.append(((info.mode & 0004) != 0) ? 'r' : '-');
   5075                 b.append(((info.mode & 0002) != 0) ? 'w' : '-');
   5076                 b.append(((info.mode & 0001) != 0) ? 'x' : '-');
   5077                 b.append(String.format(" %9d ", info.size));
   5078 
   5079                 Date stamp = new Date(info.mtime);
   5080                 b.append(new SimpleDateFormat("MMM dd HH:mm:ss ").format(stamp));
   5081 
   5082                 b.append(info.packageName);
   5083                 b.append(" :: ");
   5084                 b.append(info.domain);
   5085                 b.append(" :: ");
   5086                 b.append(info.path);
   5087 
   5088                 Slog.i(TAG, b.toString());
   5089             }
   5090         }
   5091 
   5092         // Consume a tar file header block [sequence] and accumulate the relevant metadata
   5093         FileMetadata readTarHeaders(InputStream instream) throws IOException {
   5094             byte[] block = new byte[512];
   5095             FileMetadata info = null;
   5096 
   5097             boolean gotHeader = readTarHeader(instream, block);
   5098             if (gotHeader) {
   5099                 try {
   5100                     // okay, presume we're okay, and extract the various metadata
   5101                     info = new FileMetadata();
   5102                     info.size = extractRadix(block, 124, 12, 8);
   5103                     info.mtime = extractRadix(block, 136, 12, 8);
   5104                     info.mode = extractRadix(block, 100, 8, 8);
   5105 
   5106                     info.path = extractString(block, 345, 155); // prefix
   5107                     String path = extractString(block, 0, 100);
   5108                     if (path.length() > 0) {
   5109                         if (info.path.length() > 0) info.path += '/';
   5110                         info.path += path;
   5111                     }
   5112 
   5113                     // tar link indicator field: 1 byte at offset 156 in the header.
   5114                     int typeChar = block[156];
   5115                     if (typeChar == 'x') {
   5116                         // pax extended header, so we need to read that
   5117                         gotHeader = readPaxExtendedHeader(instream, info);
   5118                         if (gotHeader) {
   5119                             // and after a pax extended header comes another real header -- read
   5120                             // that to find the real file type
   5121                             gotHeader = readTarHeader(instream, block);
   5122                         }
   5123                         if (!gotHeader) throw new IOException("Bad or missing pax header");
   5124 
   5125                         typeChar = block[156];
   5126                     }
   5127 
   5128                     switch (typeChar) {
   5129                         case '0': info.type = BackupAgent.TYPE_FILE; break;
   5130                         case '5': {
   5131                             info.type = BackupAgent.TYPE_DIRECTORY;
   5132                             if (info.size != 0) {
   5133                                 Slog.w(TAG, "Directory entry with nonzero size in header");
   5134                                 info.size = 0;
   5135                             }
   5136                             break;
   5137                         }
   5138                         case 0: {
   5139                             // presume EOF
   5140                             if (DEBUG) Slog.w(TAG, "Saw type=0 in tar header block, info=" + info);
   5141                             return null;
   5142                         }
   5143                         default: {
   5144                             Slog.e(TAG, "Unknown tar entity type: " + typeChar);
   5145                             throw new IOException("Unknown entity type " + typeChar);
   5146                         }
   5147                     }
   5148 
   5149                     // Parse out the path
   5150                     //
   5151                     // first: apps/shared/unrecognized
   5152                     if (FullBackup.SHARED_PREFIX.regionMatches(0,
   5153                             info.path, 0, FullBackup.SHARED_PREFIX.length())) {
   5154                         // File in shared storage.  !!! TODO: implement this.
   5155                         info.path = info.path.substring(FullBackup.SHARED_PREFIX.length());
   5156                         info.packageName = SHARED_BACKUP_AGENT_PACKAGE;
   5157                         info.domain = FullBackup.SHARED_STORAGE_TOKEN;
   5158                         if (DEBUG) Slog.i(TAG, "File in shared storage: " + info.path);
   5159                     } else if (FullBackup.APPS_PREFIX.regionMatches(0,
   5160                             info.path, 0, FullBackup.APPS_PREFIX.length())) {
   5161                         // App content!  Parse out the package name and domain
   5162 
   5163                         // strip the apps/ prefix
   5164                         info.path = info.path.substring(FullBackup.APPS_PREFIX.length());
   5165 
   5166                         // extract the package name
   5167                         int slash = info.path.indexOf('/');
   5168                         if (slash < 0) throw new IOException("Illegal semantic path in " + info.path);
   5169                         info.packageName = info.path.substring(0, slash);
   5170                         info.path = info.path.substring(slash+1);
   5171 
   5172                         // if it's a manifest or metadata payload we're done, otherwise parse
   5173                         // out the domain into which the file will be restored
   5174                         if (!info.path.equals(BACKUP_MANIFEST_FILENAME)
   5175                                 && !info.path.equals(BACKUP_METADATA_FILENAME)) {
   5176                             slash = info.path.indexOf('/');
   5177                             if (slash < 0) {
   5178                                 throw new IOException("Illegal semantic path in non-manifest "
   5179                                         + info.path);
   5180                             }
   5181                             info.domain = info.path.substring(0, slash);
   5182                             info.path = info.path.substring(slash + 1);
   5183                         }
   5184                     }
   5185                 } catch (IOException e) {
   5186                     if (DEBUG) {
   5187                         Slog.e(TAG, "Parse error in header: " + e.getMessage());
   5188                         HEXLOG(block);
   5189                     }
   5190                     throw e;
   5191                 }
   5192             }
   5193             return info;
   5194         }
   5195 
   5196         private boolean isRestorableFile(FileMetadata info) {
   5197             if (FullBackup.CACHE_TREE_TOKEN.equals(info.domain)) {
   5198                 if (MORE_DEBUG) {
   5199                     Slog.i(TAG, "Dropping cache file path " + info.path);
   5200                 }
   5201                 return false;
   5202             }
   5203 
   5204             if (FullBackup.ROOT_TREE_TOKEN.equals(info.domain)) {
   5205                 // It's possible this is "no-backup" dir contents in an archive stream
   5206                 // produced on a device running a version of the OS that predates that
   5207                 // API.  Respect the no-backup intention and don't let the data get to
   5208                 // the app.
   5209                 if (info.path.startsWith("no_backup/")) {
   5210                     if (MORE_DEBUG) {
   5211                         Slog.i(TAG, "Dropping no_backup file path " + info.path);
   5212                     }
   5213                     return false;
   5214                 }
   5215             }
   5216 
   5217             // The path needs to be canonical
   5218             if (info.path.contains("..") || info.path.contains("//")) {
   5219                 if (MORE_DEBUG) {
   5220                     Slog.w(TAG, "Dropping invalid path " + info.path);
   5221                 }
   5222                 return false;
   5223             }
   5224 
   5225             // Otherwise we think this file is good to go
   5226             return true;
   5227         }
   5228 
   5229         private void HEXLOG(byte[] block) {
   5230             int offset = 0;
   5231             int todo = block.length;
   5232             StringBuilder buf = new StringBuilder(64);
   5233             while (todo > 0) {
   5234                 buf.append(String.format("%04x   ", offset));
   5235                 int numThisLine = (todo > 16) ? 16 : todo;
   5236                 for (int i = 0; i < numThisLine; i++) {
   5237                     buf.append(String.format("%02x ", block[offset+i]));
   5238                 }
   5239                 Slog.i("hexdump", buf.toString());
   5240                 buf.setLength(0);
   5241                 todo -= numThisLine;
   5242                 offset += numThisLine;
   5243             }
   5244         }
   5245 
   5246         // Read exactly the given number of bytes into a buffer at the stated offset.
   5247         // Returns false if EOF is encountered before the requested number of bytes
   5248         // could be read.
   5249         int readExactly(InputStream in, byte[] buffer, int offset, int size)
   5250                 throws IOException {
   5251             if (size <= 0) throw new IllegalArgumentException("size must be > 0");
   5252 if (MORE_DEBUG) Slog.i(TAG, "  ... readExactly(" + size + ") called");
   5253             int soFar = 0;
   5254             while (soFar < size) {
   5255                 int nRead = in.read(buffer, offset + soFar, size - soFar);
   5256                 if (nRead <= 0) {
   5257                     if (MORE_DEBUG) Slog.w(TAG, "- wanted exactly " + size + " but got only " + soFar);
   5258                     break;
   5259                 }
   5260                 soFar += nRead;
   5261 if (MORE_DEBUG) Slog.v(TAG, "   + got " + nRead + "; now wanting " + (size - soFar));
   5262             }
   5263             return soFar;
   5264         }
   5265 
   5266         boolean readTarHeader(InputStream instream, byte[] block) throws IOException {
   5267             final int got = readExactly(instream, block, 0, 512);
   5268             if (got == 0) return false;     // Clean EOF
   5269             if (got < 512) throw new IOException("Unable to read full block header");
   5270             mBytes += 512;
   5271             return true;
   5272         }
   5273 
   5274         // overwrites 'info' fields based on the pax extended header
   5275         boolean readPaxExtendedHeader(InputStream instream, FileMetadata info)
   5276                 throws IOException {
   5277             // We should never see a pax extended header larger than this
   5278             if (info.size > 32*1024) {
   5279                 Slog.w(TAG, "Suspiciously large pax header size " + info.size
   5280                         + " - aborting");
   5281                 throw new IOException("Sanity failure: pax header size " + info.size);
   5282             }
   5283 
   5284             // read whole blocks, not just the content size
   5285             int numBlocks = (int)((info.size + 511) >> 9);
   5286             byte[] data = new byte[numBlocks * 512];
   5287             if (readExactly(instream, data, 0, data.length) < data.length) {
   5288                 throw new IOException("Unable to read full pax header");
   5289             }
   5290             mBytes += data.length;
   5291 
   5292             final int contentSize = (int) info.size;
   5293             int offset = 0;
   5294             do {
   5295                 // extract the line at 'offset'
   5296                 int eol = offset+1;
   5297                 while (eol < contentSize && data[eol] != ' ') eol++;
   5298                 if (eol >= contentSize) {
   5299                     // error: we just hit EOD looking for the end of the size field
   5300                     throw new IOException("Invalid pax data");
   5301                 }
   5302                 // eol points to the space between the count and the key
   5303                 int linelen = (int) extractRadix(data, offset, eol - offset, 10);
   5304                 int key = eol + 1;  // start of key=value
   5305                 eol = offset + linelen - 1; // trailing LF
   5306                 int value;
   5307                 for (value = key+1; data[value] != '=' && value <= eol; value++);
   5308                 if (value > eol) {
   5309                     throw new IOException("Invalid pax declaration");
   5310                 }
   5311 
   5312                 // pax requires that key/value strings be in UTF-8
   5313                 String keyStr = new String(data, key, value-key, "UTF-8");
   5314                 // -1 to strip the trailing LF
   5315                 String valStr = new String(data, value+1, eol-value-1, "UTF-8");
   5316 
   5317                 if ("path".equals(keyStr)) {
   5318                     info.path = valStr;
   5319                 } else if ("size".equals(keyStr)) {
   5320                     info.size = Long.parseLong(valStr);
   5321                 } else {
   5322                     if (DEBUG) Slog.i(TAG, "Unhandled pax key: " + key);
   5323                 }
   5324 
   5325                 offset += linelen;
   5326             } while (offset < contentSize);
   5327 
   5328             return true;
   5329         }
   5330 
   5331         long extractRadix(byte[] data, int offset, int maxChars, int radix)
   5332                 throws IOException {
   5333             long value = 0;
   5334             final int end = offset + maxChars;
   5335             for (int i = offset; i < end; i++) {
   5336                 final byte b = data[i];
   5337                 // Numeric fields in tar can terminate with either NUL or SPC
   5338                 if (b == 0 || b == ' ') break;
   5339                 if (b < '0' || b > ('0' + radix - 1)) {
   5340                     throw new IOException("Invalid number in header: '" + (char)b
   5341                             + "' for radix " + radix);
   5342                 }
   5343                 value = radix * value + (b - '0');
   5344             }
   5345             return value;
   5346         }
   5347 
   5348         String extractString(byte[] data, int offset, int maxChars) throws IOException {
   5349             final int end = offset + maxChars;
   5350             int eos = offset;
   5351             // tar string fields terminate early with a NUL
   5352             while (eos < end && data[eos] != 0) eos++;
   5353             return new String(data, offset, eos-offset, "US-ASCII");
   5354         }
   5355 
   5356         void sendStartRestore() {
   5357             if (mObserver != null) {
   5358                 try {
   5359                     mObserver.onStartRestore();
   5360                 } catch (RemoteException e) {
   5361                     Slog.w(TAG, "full restore observer went away: startRestore");
   5362                     mObserver = null;
   5363                 }
   5364             }
   5365         }
   5366 
   5367         void sendOnRestorePackage(String name) {
   5368             if (mObserver != null) {
   5369                 try {
   5370                     // TODO: use a more user-friendly name string
   5371                     mObserver.onRestorePackage(name);
   5372                 } catch (RemoteException e) {
   5373                     Slog.w(TAG, "full restore observer went away: restorePackage");
   5374                     mObserver = null;
   5375                 }
   5376             }
   5377         }
   5378 
   5379         void sendEndRestore() {
   5380             if (mObserver != null) {
   5381                 try {
   5382                     mObserver.onEndRestore();
   5383                 } catch (RemoteException e) {
   5384                     Slog.w(TAG, "full restore observer went away: endRestore");
   5385                     mObserver = null;
   5386                 }
   5387             }
   5388         }
   5389     }
   5390 
   5391     // ***** end new engine class ***
   5392 
   5393     class PerformAdbRestoreTask implements Runnable {
   5394         ParcelFileDescriptor mInputFile;
   5395         String mCurrentPassword;
   5396         String mDecryptPassword;
   5397         IFullBackupRestoreObserver mObserver;
   5398         AtomicBoolean mLatchObject;
   5399         IBackupAgent mAgent;
   5400         String mAgentPackage;
   5401         ApplicationInfo mTargetApp;
   5402         FullBackupObbConnection mObbConnection = null;
   5403         ParcelFileDescriptor[] mPipes = null;
   5404         byte[] mWidgetData = null;
   5405 
   5406         long mBytes;
   5407 
   5408         // possible handling states for a given package in the restore dataset
   5409         final HashMap<String, RestorePolicy> mPackagePolicies
   5410                 = new HashMap<String, RestorePolicy>();
   5411 
   5412         // installer package names for each encountered app, derived from the manifests
   5413         final HashMap<String, String> mPackageInstallers = new HashMap<String, String>();
   5414 
   5415         // Signatures for a given package found in its manifest file
   5416         final HashMap<String, Signature[]> mManifestSignatures
   5417                 = new HashMap<String, Signature[]>();
   5418 
   5419         // Packages we've already wiped data on when restoring their first file
   5420         final HashSet<String> mClearedPackages = new HashSet<String>();
   5421 
   5422         PerformAdbRestoreTask(ParcelFileDescriptor fd, String curPassword, String decryptPassword,
   5423                 IFullBackupRestoreObserver observer, AtomicBoolean latch) {
   5424             mInputFile = fd;
   5425             mCurrentPassword = curPassword;
   5426             mDecryptPassword = decryptPassword;
   5427             mObserver = observer;
   5428             mLatchObject = latch;
   5429             mAgent = null;
   5430             mAgentPackage = null;
   5431             mTargetApp = null;
   5432             mObbConnection = new FullBackupObbConnection();
   5433 
   5434             // Which packages we've already wiped data on.  We prepopulate this
   5435             // with a whitelist of packages known to be unclearable.
   5436             mClearedPackages.add("android");
   5437             mClearedPackages.add(SETTINGS_PACKAGE);
   5438         }
   5439 
   5440         class RestoreFileRunnable implements Runnable {
   5441             IBackupAgent mAgent;
   5442             FileMetadata mInfo;
   5443             ParcelFileDescriptor mSocket;
   5444             int mToken;
   5445 
   5446             RestoreFileRunnable(IBackupAgent agent, FileMetadata info,
   5447                     ParcelFileDescriptor socket, int token) throws IOException {
   5448                 mAgent = agent;
   5449                 mInfo = info;
   5450                 mToken = token;
   5451 
   5452                 // This class is used strictly for process-local binder invocations.  The
   5453                 // semantics of ParcelFileDescriptor differ in this case; in particular, we
   5454                 // do not automatically get a 'dup'ed descriptor that we can can continue
   5455                 // to use asynchronously from the caller.  So, we make sure to dup it ourselves
   5456                 // before proceeding to do the restore.
   5457                 mSocket = ParcelFileDescriptor.dup(socket.getFileDescriptor());
   5458             }
   5459 
   5460             @Override
   5461             public void run() {
   5462                 try {
   5463                     mAgent.doRestoreFile(mSocket, mInfo.size, mInfo.type,
   5464                             mInfo.domain, mInfo.path, mInfo.mode, mInfo.mtime,
   5465                             mToken, mBackupManagerBinder);
   5466                 } catch (RemoteException e) {
   5467                     // never happens; this is used strictly for local binder calls
   5468                 }
   5469             }
   5470         }
   5471 
   5472         @Override
   5473         public void run() {
   5474             Slog.i(TAG, "--- Performing full-dataset restore ---");
   5475             mObbConnection.establish();
   5476             sendStartRestore();
   5477 
   5478             // Are we able to restore shared-storage data?
   5479             if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
   5480                 mPackagePolicies.put(SHARED_BACKUP_AGENT_PACKAGE, RestorePolicy.ACCEPT);
   5481             }
   5482 
   5483             FileInputStream rawInStream = null;
   5484             DataInputStream rawDataIn = null;
   5485             try {
   5486                 if (!backupPasswordMatches(mCurrentPassword)) {
   5487                     if (DEBUG) Slog.w(TAG, "Backup password mismatch; aborting");
   5488                     return;
   5489                 }
   5490 
   5491                 mBytes = 0;
   5492                 byte[] buffer = new byte[32 * 1024];
   5493                 rawInStream = new FileInputStream(mInputFile.getFileDescriptor());
   5494                 rawDataIn = new DataInputStream(rawInStream);
   5495 
   5496                 // First, parse out the unencrypted/uncompressed header
   5497                 boolean compressed = false;
   5498                 InputStream preCompressStream = rawInStream;
   5499                 final InputStream in;
   5500 
   5501                 boolean okay = false;
   5502                 final int headerLen = BACKUP_FILE_HEADER_MAGIC.length();
   5503                 byte[] streamHeader = new byte[headerLen];
   5504                 rawDataIn.readFully(streamHeader);
   5505                 byte[] magicBytes = BACKUP_FILE_HEADER_MAGIC.getBytes("UTF-8");
   5506                 if (Arrays.equals(magicBytes, streamHeader)) {
   5507                     // okay, header looks good.  now parse out the rest of the fields.
   5508                     String s = readHeaderLine(rawInStream);
   5509                     final int archiveVersion = Integer.parseInt(s);
   5510                     if (archiveVersion <= BACKUP_FILE_VERSION) {
   5511                         // okay, it's a version we recognize.  if it's version 1, we may need
   5512                         // to try two different PBKDF2 regimes to compare checksums.
   5513                         final boolean pbkdf2Fallback = (archiveVersion == 1);
   5514 
   5515                         s = readHeaderLine(rawInStream);
   5516                         compressed = (Integer.parseInt(s) != 0);
   5517                         s = readHeaderLine(rawInStream);
   5518                         if (s.equals("none")) {
   5519                             // no more header to parse; we're good to go
   5520                             okay = true;
   5521                         } else if (mDecryptPassword != null && mDecryptPassword.length() > 0) {
   5522                             preCompressStream = decodeAesHeaderAndInitialize(s, pbkdf2Fallback,
   5523                                     rawInStream);
   5524                             if (preCompressStream != null) {
   5525                                 okay = true;
   5526                             }
   5527                         } else Slog.w(TAG, "Archive is encrypted but no password given");
   5528                     } else Slog.w(TAG, "Wrong header version: " + s);
   5529                 } else Slog.w(TAG, "Didn't read the right header magic");
   5530 
   5531                 if (!okay) {
   5532                     Slog.w(TAG, "Invalid restore data; aborting.");
   5533                     return;
   5534                 }
   5535 
   5536                 // okay, use the right stream layer based on compression
   5537                 in = (compressed) ? new InflaterInputStream(preCompressStream) : preCompressStream;
   5538 
   5539                 boolean didRestore;
   5540                 do {
   5541                     didRestore = restoreOneFile(in, buffer);
   5542                 } while (didRestore);
   5543 
   5544                 if (MORE_DEBUG) Slog.v(TAG, "Done consuming input tarfile, total bytes=" + mBytes);
   5545             } catch (IOException e) {
   5546                 Slog.e(TAG, "Unable to read restore input");
   5547             } finally {
   5548                 tearDownPipes();
   5549                 tearDownAgent(mTargetApp);
   5550 
   5551                 try {
   5552                     if (rawDataIn != null) rawDataIn.close();
   5553                     if (rawInStream != null) rawInStream.close();
   5554                     mInputFile.close();
   5555                 } catch (IOException e) {
   5556                     Slog.w(TAG, "Close of restore data pipe threw", e);
   5557                     /* nothing we can do about this */
   5558                 }
   5559                 synchronized (mCurrentOpLock) {
   5560                     mCurrentOperations.clear();
   5561                 }
   5562                 synchronized (mLatchObject) {
   5563                     mLatchObject.set(true);
   5564                     mLatchObject.notifyAll();
   5565                 }
   5566                 mObbConnection.tearDown();
   5567                 sendEndRestore();
   5568                 Slog.d(TAG, "Full restore pass complete.");
   5569                 mWakelock.release();
   5570             }
   5571         }
   5572 
   5573         String readHeaderLine(InputStream in) throws IOException {
   5574             int c;
   5575             StringBuilder buffer = new StringBuilder(80);
   5576             while ((c = in.read()) >= 0) {
   5577                 if (c == '\n') break;   // consume and discard the newlines
   5578                 buffer.append((char)c);
   5579             }
   5580             return buffer.toString();
   5581         }
   5582 
   5583         InputStream attemptMasterKeyDecryption(String algorithm, byte[] userSalt, byte[] ckSalt,
   5584                 int rounds, String userIvHex, String masterKeyBlobHex, InputStream rawInStream,
   5585                 boolean doLog) {
   5586             InputStream result = null;
   5587 
   5588             try {
   5589                 Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
   5590                 SecretKey userKey = buildPasswordKey(algorithm, mDecryptPassword, userSalt,
   5591                         rounds);
   5592                 byte[] IV = hexToByteArray(userIvHex);
   5593                 IvParameterSpec ivSpec = new IvParameterSpec(IV);
   5594                 c.init(Cipher.DECRYPT_MODE,
   5595                         new SecretKeySpec(userKey.getEncoded(), "AES"),
   5596                         ivSpec);
   5597                 byte[] mkCipher = hexToByteArray(masterKeyBlobHex);
   5598                 byte[] mkBlob = c.doFinal(mkCipher);
   5599 
   5600                 // first, the master key IV
   5601                 int offset = 0;
   5602                 int len = mkBlob[offset++];
   5603                 IV = Arrays.copyOfRange(mkBlob, offset, offset + len);
   5604                 offset += len;
   5605                 // then the master key itself
   5606                 len = mkBlob[offset++];
   5607                 byte[] mk = Arrays.copyOfRange(mkBlob,
   5608                         offset, offset + len);
   5609                 offset += len;
   5610                 // and finally the master key checksum hash
   5611                 len = mkBlob[offset++];
   5612                 byte[] mkChecksum = Arrays.copyOfRange(mkBlob,
   5613                         offset, offset + len);
   5614 
   5615                 // now validate the decrypted master key against the checksum
   5616                 byte[] calculatedCk = makeKeyChecksum(algorithm, mk, ckSalt, rounds);
   5617                 if (Arrays.equals(calculatedCk, mkChecksum)) {
   5618                     ivSpec = new IvParameterSpec(IV);
   5619                     c.init(Cipher.DECRYPT_MODE,
   5620                             new SecretKeySpec(mk, "AES"),
   5621                             ivSpec);
   5622                     // Only if all of the above worked properly will 'result' be assigned
   5623                     result = new CipherInputStream(rawInStream, c);
   5624                 } else if (doLog) Slog.w(TAG, "Incorrect password");
   5625             } catch (InvalidAlgorithmParameterException e) {
   5626                 if (doLog) Slog.e(TAG, "Needed parameter spec unavailable!", e);
   5627             } catch (BadPaddingException e) {
   5628                 // This case frequently occurs when the wrong password is used to decrypt
   5629                 // the master key.  Use the identical "incorrect password" log text as is
   5630                 // used in the checksum failure log in order to avoid providing additional
   5631                 // information to an attacker.
   5632                 if (doLog) Slog.w(TAG, "Incorrect password");
   5633             } catch (IllegalBlockSizeException e) {
   5634                 if (doLog) Slog.w(TAG, "Invalid block size in master key");
   5635             } catch (NoSuchAlgorithmException e) {
   5636                 if (doLog) Slog.e(TAG, "Needed decryption algorithm unavailable!");
   5637             } catch (NoSuchPaddingException e) {
   5638                 if (doLog) Slog.e(TAG, "Needed padding mechanism unavailable!");
   5639             } catch (InvalidKeyException e) {
   5640                 if (doLog) Slog.w(TAG, "Illegal password; aborting");
   5641             }
   5642 
   5643             return result;
   5644         }
   5645 
   5646         InputStream decodeAesHeaderAndInitialize(String encryptionName, boolean pbkdf2Fallback,
   5647                 InputStream rawInStream) {
   5648             InputStream result = null;
   5649             try {
   5650                 if (encryptionName.equals(ENCRYPTION_ALGORITHM_NAME)) {
   5651 
   5652                     String userSaltHex = readHeaderLine(rawInStream); // 5
   5653                     byte[] userSalt = hexToByteArray(userSaltHex);
   5654 
   5655                     String ckSaltHex = readHeaderLine(rawInStream); // 6
   5656                     byte[] ckSalt = hexToByteArray(ckSaltHex);
   5657 
   5658                     int rounds = Integer.parseInt(readHeaderLine(rawInStream)); // 7
   5659                     String userIvHex = readHeaderLine(rawInStream); // 8
   5660 
   5661                     String masterKeyBlobHex = readHeaderLine(rawInStream); // 9
   5662 
   5663                     // decrypt the master key blob
   5664                     result = attemptMasterKeyDecryption(PBKDF_CURRENT, userSalt, ckSalt,
   5665                             rounds, userIvHex, masterKeyBlobHex, rawInStream, false);
   5666                     if (result == null && pbkdf2Fallback) {
   5667                         result = attemptMasterKeyDecryption(PBKDF_FALLBACK, userSalt, ckSalt,
   5668                                 rounds, userIvHex, masterKeyBlobHex, rawInStream, true);
   5669                     }
   5670                 } else Slog.w(TAG, "Unsupported encryption method: " + encryptionName);
   5671             } catch (NumberFormatException e) {
   5672                 Slog.w(TAG, "Can't parse restore data header");
   5673             } catch (IOException e) {
   5674                 Slog.w(TAG, "Can't read input header");
   5675             }
   5676 
   5677             return result;
   5678         }
   5679 
   5680         boolean restoreOneFile(InputStream instream, byte[] buffer) {
   5681             FileMetadata info;
   5682             try {
   5683                 info = readTarHeaders(instream);
   5684                 if (info != null) {
   5685                     if (MORE_DEBUG) {
   5686                         dumpFileMetadata(info);
   5687                     }
   5688 
   5689                     final String pkg = info.packageName;
   5690                     if (!pkg.equals(mAgentPackage)) {
   5691                         // okay, change in package; set up our various
   5692                         // bookkeeping if we haven't seen it yet
   5693                         if (!mPackagePolicies.containsKey(pkg)) {
   5694                             mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
   5695                         }
   5696 
   5697                         // Clean up the previous agent relationship if necessary,
   5698                         // and let the observer know we're considering a new app.
   5699                         if (mAgent != null) {
   5700                             if (DEBUG) Slog.d(TAG, "Saw new package; finalizing old one");
   5701                             // Now we're really done
   5702                             tearDownPipes();
   5703                             tearDownAgent(mTargetApp);
   5704                             mTargetApp = null;
   5705                             mAgentPackage = null;
   5706                         }
   5707                     }
   5708 
   5709                     if (info.path.equals(BACKUP_MANIFEST_FILENAME)) {
   5710                         mPackagePolicies.put(pkg, readAppManifest(info, instream));
   5711                         mPackageInstallers.put(pkg, info.installerPackageName);
   5712                         // We've read only the manifest content itself at this point,
   5713                         // so consume the footer before looping around to the next
   5714                         // input file
   5715                         skipTarPadding(info.size, instream);
   5716                         sendOnRestorePackage(pkg);
   5717                     } else if (info.path.equals(BACKUP_METADATA_FILENAME)) {
   5718                         // Metadata blobs!
   5719                         readMetadata(info, instream);
   5720                         skipTarPadding(info.size, instream);
   5721                     } else {
   5722                         // Non-manifest, so it's actual file data.  Is this a package
   5723                         // we're ignoring?
   5724                         boolean okay = true;
   5725                         RestorePolicy policy = mPackagePolicies.get(pkg);
   5726                         switch (policy) {
   5727                             case IGNORE:
   5728                                 okay = false;
   5729                                 break;
   5730 
   5731                             case ACCEPT_IF_APK:
   5732                                 // If we're in accept-if-apk state, then the first file we
   5733                                 // see MUST be the apk.
   5734                                 if (info.domain.equals(FullBackup.APK_TREE_TOKEN)) {
   5735                                     if (DEBUG) Slog.d(TAG, "APK file; installing");
   5736                                     // Try to install the app.
   5737                                     String installerName = mPackageInstallers.get(pkg);
   5738                                     okay = installApk(info, installerName, instream);
   5739                                     // good to go; promote to ACCEPT
   5740                                     mPackagePolicies.put(pkg, (okay)
   5741                                             ? RestorePolicy.ACCEPT
   5742                                             : RestorePolicy.IGNORE);
   5743                                     // At this point we've consumed this file entry
   5744                                     // ourselves, so just strip the tar footer and
   5745                                     // go on to the next file in the input stream
   5746                                     skipTarPadding(info.size, instream);
   5747                                     return true;
   5748                                 } else {
   5749                                     // File data before (or without) the apk.  We can't
   5750                                     // handle it coherently in this case so ignore it.
   5751                                     mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
   5752                                     okay = false;
   5753                                 }
   5754                                 break;
   5755 
   5756                             case ACCEPT:
   5757                                 if (info.domain.equals(FullBackup.APK_TREE_TOKEN)) {
   5758                                     if (DEBUG) Slog.d(TAG, "apk present but ACCEPT");
   5759                                     // we can take the data without the apk, so we
   5760                                     // *want* to do so.  skip the apk by declaring this
   5761                                     // one file not-okay without changing the restore
   5762                                     // policy for the package.
   5763                                     okay = false;
   5764                                 }
   5765                                 break;
   5766 
   5767                             default:
   5768                                 // Something has gone dreadfully wrong when determining
   5769                                 // the restore policy from the manifest.  Ignore the
   5770                                 // rest of this package's data.
   5771                                 Slog.e(TAG, "Invalid policy from manifest");
   5772                                 okay = false;
   5773                                 mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
   5774                                 break;
   5775                         }
   5776 
   5777                         // The path needs to be canonical
   5778                         if (info.path.contains("..") || info.path.contains("//")) {
   5779                             if (MORE_DEBUG) {
   5780                                 Slog.w(TAG, "Dropping invalid path " + info.path);
   5781                             }
   5782                             okay = false;
   5783                         }
   5784 
   5785                         // If the policy is satisfied, go ahead and set up to pipe the
   5786                         // data to the agent.
   5787                         if (DEBUG && okay && mAgent != null) {
   5788                             Slog.i(TAG, "Reusing existing agent instance");
   5789                         }
   5790                         if (okay && mAgent == null) {
   5791                             if (DEBUG) Slog.d(TAG, "Need to launch agent for " + pkg);
   5792 
   5793                             try {
   5794                                 mTargetApp = mPackageManager.getApplicationInfo(pkg, 0);
   5795 
   5796                                 // If we haven't sent any data to this app yet, we probably
   5797                                 // need to clear it first.  Check that.
   5798                                 if (!mClearedPackages.contains(pkg)) {
   5799                                     // apps with their own backup agents are
   5800                                     // responsible for coherently managing a full
   5801                                     // restore.
   5802                                     if (mTargetApp.backupAgentName == null) {
   5803                                         if (DEBUG) Slog.d(TAG, "Clearing app data preparatory to full restore");
   5804                                         clearApplicationDataSynchronous(pkg);
   5805                                     } else {
   5806                                         if (DEBUG) Slog.d(TAG, "backup agent ("
   5807                                                 + mTargetApp.backupAgentName + ") => no clear");
   5808                                     }
   5809                                     mClearedPackages.add(pkg);
   5810                                 } else {
   5811                                     if (DEBUG) Slog.d(TAG, "We've initialized this app already; no clear required");
   5812                                 }
   5813 
   5814                                 // All set; now set up the IPC and launch the agent
   5815                                 setUpPipes();
   5816                                 mAgent = bindToAgentSynchronous(mTargetApp,
   5817                                         IApplicationThread.BACKUP_MODE_RESTORE_FULL);
   5818                                 mAgentPackage = pkg;
   5819                             } catch (IOException e) {
   5820                                 // fall through to error handling
   5821                             } catch (NameNotFoundException e) {
   5822                                 // fall through to error handling
   5823                             }
   5824 
   5825                             if (mAgent == null) {
   5826                                 if (DEBUG) Slog.d(TAG, "Unable to create agent for " + pkg);
   5827                                 okay = false;
   5828                                 tearDownPipes();
   5829                                 mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
   5830                             }
   5831                         }
   5832 
   5833                         // Sanity check: make sure we never give data to the wrong app.  This
   5834                         // should never happen but a little paranoia here won't go amiss.
   5835                         if (okay && !pkg.equals(mAgentPackage)) {
   5836                             Slog.e(TAG, "Restoring data for " + pkg
   5837                                     + " but agent is for " + mAgentPackage);
   5838                             okay = false;
   5839                         }
   5840 
   5841                         // At this point we have an agent ready to handle the full
   5842                         // restore data as well as a pipe for sending data to
   5843                         // that agent.  Tell the agent to start reading from the
   5844                         // pipe.
   5845                         if (okay) {
   5846                             boolean agentSuccess = true;
   5847                             long toCopy = info.size;
   5848                             final int token = generateToken();
   5849                             try {
   5850                                 prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL, null);
   5851                                 if (info.domain.equals(FullBackup.OBB_TREE_TOKEN)) {
   5852                                     if (DEBUG) Slog.d(TAG, "Restoring OBB file for " + pkg
   5853                                             + " : " + info.path);
   5854                                     mObbConnection.restoreObbFile(pkg, mPipes[0],
   5855                                             info.size, info.type, info.path, info.mode,
   5856                                             info.mtime, token, mBackupManagerBinder);
   5857                                 } else {
   5858                                     if (DEBUG) Slog.d(TAG, "Invoking agent to restore file "
   5859                                             + info.path);
   5860                                     // fire up the app's agent listening on the socket.  If
   5861                                     // the agent is running in the system process we can't
   5862                                     // just invoke it asynchronously, so we provide a thread
   5863                                     // for it here.
   5864                                     if (mTargetApp.processName.equals("system")) {
   5865                                         Slog.d(TAG, "system process agent - spinning a thread");
   5866                                         RestoreFileRunnable runner = new RestoreFileRunnable(
   5867                                                 mAgent, info, mPipes[0], token);
   5868                                         new Thread(runner, "restore-sys-runner").start();
   5869                                     } else {
   5870                                         mAgent.doRestoreFile(mPipes[0], info.size, info.type,
   5871                                                 info.domain, info.path, info.mode, info.mtime,
   5872                                                 token, mBackupManagerBinder);
   5873                                     }
   5874                                 }
   5875                             } catch (IOException e) {
   5876                                 // couldn't dup the socket for a process-local restore
   5877                                 Slog.d(TAG, "Couldn't establish restore");
   5878                                 agentSuccess = false;
   5879                                 okay = false;
   5880                             } catch (RemoteException e) {
   5881                                 // whoops, remote entity went away.  We'll eat the content
   5882                                 // ourselves, then, and not copy it over.
   5883                                 Slog.e(TAG, "Agent crashed during full restore");
   5884                                 agentSuccess = false;
   5885                                 okay = false;
   5886                             }
   5887 
   5888                             // Copy over the data if the agent is still good
   5889                             if (okay) {
   5890                                 boolean pipeOkay = true;
   5891                                 FileOutputStream pipe = new FileOutputStream(
   5892                                         mPipes[1].getFileDescriptor());
   5893                                 while (toCopy > 0) {
   5894                                     int toRead = (toCopy > buffer.length)
   5895                                     ? buffer.length : (int)toCopy;
   5896                                     int nRead = instream.read(buffer, 0, toRead);
   5897                                     if (nRead >= 0) mBytes += nRead;
   5898                                     if (nRead <= 0) break;
   5899                                     toCopy -= nRead;
   5900 
   5901                                     // send it to the output pipe as long as things
   5902                                     // are still good
   5903                                     if (pipeOkay) {
   5904                                         try {
   5905                                             pipe.write(buffer, 0, nRead);
   5906                                         } catch (IOException e) {
   5907                                             Slog.e(TAG, "Failed to write to restore pipe", e);
   5908                                             pipeOkay = false;
   5909                                         }
   5910                                     }
   5911                                 }
   5912 
   5913                                 // done sending that file!  Now we just need to consume
   5914                                 // the delta from info.size to the end of block.
   5915                                 skipTarPadding(info.size, instream);
   5916 
   5917                                 // and now that we've sent it all, wait for the remote
   5918                                 // side to acknowledge receipt
   5919                                 agentSuccess = waitUntilOperationComplete(token);
   5920                             }
   5921 
   5922                             // okay, if the remote end failed at any point, deal with
   5923                             // it by ignoring the rest of the restore on it
   5924                             if (!agentSuccess) {
   5925                                 mBackupHandler.removeMessages(MSG_TIMEOUT);
   5926                                 tearDownPipes();
   5927                                 tearDownAgent(mTargetApp);
   5928                                 mAgent = null;
   5929                                 mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
   5930                             }
   5931                         }
   5932 
   5933                         // Problems setting up the agent communication, or an already-
   5934                         // ignored package: skip to the next tar stream entry by
   5935                         // reading and discarding this file.
   5936                         if (!okay) {
   5937                             if (DEBUG) Slog.d(TAG, "[discarding file content]");
   5938                             long bytesToConsume = (info.size + 511) & ~511;
   5939                             while (bytesToConsume > 0) {
   5940                                 int toRead = (bytesToConsume > buffer.length)
   5941                                 ? buffer.length : (int)bytesToConsume;
   5942                                 long nRead = instream.read(buffer, 0, toRead);
   5943                                 if (nRead >= 0) mBytes += nRead;
   5944                                 if (nRead <= 0) break;
   5945                                 bytesToConsume -= nRead;
   5946                             }
   5947                         }
   5948                     }
   5949                 }
   5950             } catch (IOException e) {
   5951                 if (DEBUG) Slog.w(TAG, "io exception on restore socket read", e);
   5952                 // treat as EOF
   5953                 info = null;
   5954             }
   5955 
   5956             return (info != null);
   5957         }
   5958 
   5959         void setUpPipes() throws IOException {
   5960             mPipes = ParcelFileDescriptor.createPipe();
   5961         }
   5962 
   5963         void tearDownPipes() {
   5964             if (mPipes != null) {
   5965                 try {
   5966                     mPipes[0].close();
   5967                     mPipes[0] = null;
   5968                     mPipes[1].close();
   5969                     mPipes[1] = null;
   5970                 } catch (IOException e) {
   5971                     Slog.w(TAG, "Couldn't close agent pipes", e);
   5972                 }
   5973                 mPipes = null;
   5974             }
   5975         }
   5976 
   5977         void tearDownAgent(ApplicationInfo app) {
   5978             if (mAgent != null) {
   5979                 try {
   5980                     // unbind and tidy up even on timeout or failure, just in case
   5981                     mActivityManager.unbindBackupAgent(app);
   5982 
   5983                     // The agent was running with a stub Application object, so shut it down.
   5984                     // !!! We hardcode the confirmation UI's package name here rather than use a
   5985                     //     manifest flag!  TODO something less direct.
   5986                     if (app.uid != Process.SYSTEM_UID
   5987                             && !app.packageName.equals("com.android.backupconfirm")) {
   5988                         if (DEBUG) Slog.d(TAG, "Killing host process");
   5989                         mActivityManager.killApplicationProcess(app.processName, app.uid);
   5990                     } else {
   5991                         if (DEBUG) Slog.d(TAG, "Not killing after full restore");
   5992                     }
   5993                 } catch (RemoteException e) {
   5994                     Slog.d(TAG, "Lost app trying to shut down");
   5995                 }
   5996                 mAgent = null;
   5997             }
   5998         }
   5999 
   6000         class RestoreInstallObserver extends IPackageInstallObserver.Stub {
   6001             final AtomicBoolean mDone = new AtomicBoolean();
   6002             String mPackageName;
   6003             int mResult;
   6004 
   6005             public void reset() {
   6006                 synchronized (mDone) {
   6007                     mDone.set(false);
   6008                 }
   6009             }
   6010 
   6011             public void waitForCompletion() {
   6012                 synchronized (mDone) {
   6013                     while (mDone.get() == false) {
   6014                         try {
   6015                             mDone.wait();
   6016                         } catch (InterruptedException e) { }
   6017                     }
   6018                 }
   6019             }
   6020 
   6021             int getResult() {
   6022                 return mResult;
   6023             }
   6024 
   6025             @Override
   6026             public void packageInstalled(String packageName, int returnCode)
   6027                     throws RemoteException {
   6028                 synchronized (mDone) {
   6029                     mResult = returnCode;
   6030                     mPackageName = packageName;
   6031                     mDone.set(true);
   6032                     mDone.notifyAll();
   6033                 }
   6034             }
   6035         }
   6036 
   6037         class RestoreDeleteObserver extends IPackageDeleteObserver.Stub {
   6038             final AtomicBoolean mDone = new AtomicBoolean();
   6039             int mResult;
   6040 
   6041             public void reset() {
   6042                 synchronized (mDone) {
   6043                     mDone.set(false);
   6044                 }
   6045             }
   6046 
   6047             public void waitForCompletion() {
   6048                 synchronized (mDone) {
   6049                     while (mDone.get() == false) {
   6050                         try {
   6051                             mDone.wait();
   6052                         } catch (InterruptedException e) { }
   6053                     }
   6054                 }
   6055             }
   6056 
   6057             @Override
   6058             public void packageDeleted(String packageName, int returnCode) throws RemoteException {
   6059                 synchronized (mDone) {
   6060                     mResult = returnCode;
   6061                     mDone.set(true);
   6062                     mDone.notifyAll();
   6063                 }
   6064             }
   6065         }
   6066 
   6067         final RestoreInstallObserver mInstallObserver = new RestoreInstallObserver();
   6068         final RestoreDeleteObserver mDeleteObserver = new RestoreDeleteObserver();
   6069 
   6070         boolean installApk(FileMetadata info, String installerPackage, InputStream instream) {
   6071             boolean okay = true;
   6072 
   6073             if (DEBUG) Slog.d(TAG, "Installing from backup: " + info.packageName);
   6074 
   6075             // The file content is an .apk file.  Copy it out to a staging location and
   6076             // attempt to install it.
   6077             File apkFile = new File(mDataDir, info.packageName);
   6078             try {
   6079                 FileOutputStream apkStream = new FileOutputStream(apkFile);
   6080                 byte[] buffer = new byte[32 * 1024];
   6081                 long size = info.size;
   6082                 while (size > 0) {
   6083                     long toRead = (buffer.length < size) ? buffer.length : size;
   6084                     int didRead = instream.read(buffer, 0, (int)toRead);
   6085                     if (didRead >= 0) mBytes += didRead;
   6086                     apkStream.write(buffer, 0, didRead);
   6087                     size -= didRead;
   6088                 }
   6089                 apkStream.close();
   6090 
   6091                 // make sure the installer can read it
   6092                 apkFile.setReadable(true, false);
   6093 
   6094                 // Now install it
   6095                 Uri packageUri = Uri.fromFile(apkFile);
   6096                 mInstallObserver.reset();
   6097                 mPackageManager.installPackage(packageUri, mInstallObserver,
   6098                         PackageManager.INSTALL_REPLACE_EXISTING | PackageManager.INSTALL_FROM_ADB,
   6099                         installerPackage);
   6100                 mInstallObserver.waitForCompletion();
   6101 
   6102                 if (mInstallObserver.getResult() != PackageManager.INSTALL_SUCCEEDED) {
   6103                     // The only time we continue to accept install of data even if the
   6104                     // apk install failed is if we had already determined that we could
   6105                     // accept the data regardless.
   6106                     if (mPackagePolicies.get(info.packageName) != RestorePolicy.ACCEPT) {
   6107                         okay = false;
   6108                     }
   6109                 } else {
   6110                     // Okay, the install succeeded.  Make sure it was the right app.
   6111                     boolean uninstall = false;
   6112                     if (!mInstallObserver.mPackageName.equals(info.packageName)) {
   6113                         Slog.w(TAG, "Restore stream claimed to include apk for "
   6114                                 + info.packageName + " but apk was really "
   6115                                 + mInstallObserver.mPackageName);
   6116                         // delete the package we just put in place; it might be fraudulent
   6117                         okay = false;
   6118                         uninstall = true;
   6119                     } else {
   6120                         try {
   6121                             PackageInfo pkg = mPackageManager.getPackageInfo(info.packageName,
   6122                                     PackageManager.GET_SIGNATURES);
   6123                             if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) {
   6124                                 Slog.w(TAG, "Restore stream contains apk of package "
   6125                                         + info.packageName + " but it disallows backup/restore");
   6126                                 okay = false;
   6127                             } else {
   6128                                 // So far so good -- do the signatures match the manifest?
   6129                                 Signature[] sigs = mManifestSignatures.get(info.packageName);
   6130                                 if (signaturesMatch(sigs, pkg)) {
   6131                                     // If this is a system-uid app without a declared backup agent,
   6132                                     // don't restore any of the file data.
   6133                                     if ((pkg.applicationInfo.uid < Process.FIRST_APPLICATION_UID)
   6134                                             && (pkg.applicationInfo.backupAgentName == null)) {
   6135                                         Slog.w(TAG, "Installed app " + info.packageName
   6136                                                 + " has restricted uid and no agent");
   6137                                         okay = false;
   6138                                     }
   6139                                 } else {
   6140                                     Slog.w(TAG, "Installed app " + info.packageName
   6141                                             + " signatures do not match restore manifest");
   6142                                     okay = false;
   6143                                     uninstall = true;
   6144                                 }
   6145                             }
   6146                         } catch (NameNotFoundException e) {
   6147                             Slog.w(TAG, "Install of package " + info.packageName
   6148                                     + " succeeded but now not found");
   6149                             okay = false;
   6150                         }
   6151                     }
   6152 
   6153                     // If we're not okay at this point, we need to delete the package
   6154                     // that we just installed.
   6155                     if (uninstall) {
   6156                         mDeleteObserver.reset();
   6157                         mPackageManager.deletePackage(mInstallObserver.mPackageName,
   6158                                 mDeleteObserver, 0);
   6159                         mDeleteObserver.waitForCompletion();
   6160                     }
   6161                 }
   6162             } catch (IOException e) {
   6163                 Slog.e(TAG, "Unable to transcribe restored apk for install");
   6164                 okay = false;
   6165             } finally {
   6166                 apkFile.delete();
   6167             }
   6168 
   6169             return okay;
   6170         }
   6171 
   6172         // Given an actual file content size, consume the post-content padding mandated
   6173         // by the tar format.
   6174         void skipTarPadding(long size, InputStream instream) throws IOException {
   6175             long partial = (size + 512) % 512;
   6176             if (partial > 0) {
   6177                 final int needed = 512 - (int)partial;
   6178                 byte[] buffer = new byte[needed];
   6179                 if (readExactly(instream, buffer, 0, needed) == needed) {
   6180                     mBytes += needed;
   6181                 } else throw new IOException("Unexpected EOF in padding");
   6182             }
   6183         }
   6184 
   6185         // Read a widget metadata file, returning the restored blob
   6186         void readMetadata(FileMetadata info, InputStream instream) throws IOException {
   6187             // Fail on suspiciously large widget dump files
   6188             if (info.size > 64 * 1024) {
   6189                 throw new IOException("Metadata too big; corrupt? size=" + info.size);
   6190             }
   6191 
   6192             byte[] buffer = new byte[(int) info.size];
   6193             if (readExactly(instream, buffer, 0, (int)info.size) == info.size) {
   6194                 mBytes += info.size;
   6195             } else throw new IOException("Unexpected EOF in widget data");
   6196 
   6197             String[] str = new String[1];
   6198             int offset = extractLine(buffer, 0, str);
   6199             int version = Integer.parseInt(str[0]);
   6200             if (version == BACKUP_MANIFEST_VERSION) {
   6201                 offset = extractLine(buffer, offset, str);
   6202                 final String pkg = str[0];
   6203                 if (info.packageName.equals(pkg)) {
   6204                     // Data checks out -- the rest of the buffer is a concatenation of
   6205                     // binary blobs as described in the comment at writeAppWidgetData()
   6206                     ByteArrayInputStream bin = new ByteArrayInputStream(buffer,
   6207                             offset, buffer.length - offset);
   6208                     DataInputStream in = new DataInputStream(bin);
   6209                     while (bin.available() > 0) {
   6210                         int token = in.readInt();
   6211                         int size = in.readInt();
   6212                         if (size > 64 * 1024) {
   6213                             throw new IOException("Datum "
   6214                                     + Integer.toHexString(token)
   6215                                     + " too big; corrupt? size=" + info.size);
   6216                         }
   6217                         switch (token) {
   6218                             case BACKUP_WIDGET_METADATA_TOKEN:
   6219                             {
   6220                                 if (MORE_DEBUG) {
   6221                                     Slog.i(TAG, "Got widget metadata for " + info.packageName);
   6222                                 }
   6223                                 mWidgetData = new byte[size];
   6224                                 in.read(mWidgetData);
   6225                                 break;
   6226                             }
   6227                             default:
   6228                             {
   6229                                 if (DEBUG) {
   6230                                     Slog.i(TAG, "Ignoring metadata blob "
   6231                                             + Integer.toHexString(token)
   6232                                             + " for " + info.packageName);
   6233                                 }
   6234                                 in.skipBytes(size);
   6235                                 break;
   6236                             }
   6237                         }
   6238                     }
   6239                 } else {
   6240                     Slog.w(TAG, "Metadata mismatch: package " + info.packageName
   6241                             + " but widget data for " + pkg);
   6242                 }
   6243             } else {
   6244                 Slog.w(TAG, "Unsupported metadata version " + version);
   6245             }
   6246         }
   6247 
   6248         // Returns a policy constant; takes a buffer arg to reduce memory churn
   6249         RestorePolicy readAppManifest(FileMetadata info, InputStream instream)
   6250                 throws IOException {
   6251             // Fail on suspiciously large manifest files
   6252             if (info.size > 64 * 1024) {
   6253                 throw new IOException("Restore manifest too big; corrupt? size=" + info.size);
   6254             }
   6255 
   6256             byte[] buffer = new byte[(int) info.size];
   6257             if (readExactly(instream, buffer, 0, (int)info.size) == info.size) {
   6258                 mBytes += info.size;
   6259             } else throw new IOException("Unexpected EOF in manifest");
   6260 
   6261             RestorePolicy policy = RestorePolicy.IGNORE;
   6262             String[] str = new String[1];
   6263             int offset = 0;
   6264 
   6265             try {
   6266                 offset = extractLine(buffer, offset, str);
   6267                 int version = Integer.parseInt(str[0]);
   6268                 if (version == BACKUP_MANIFEST_VERSION) {
   6269                     offset = extractLine(buffer, offset, str);
   6270                     String manifestPackage = str[0];
   6271                     // TODO: handle <original-package>
   6272                     if (manifestPackage.equals(info.packageName)) {
   6273                         offset = extractLine(buffer, offset, str);
   6274                         version = Integer.parseInt(str[0]);  // app version
   6275                         offset = extractLine(buffer, offset, str);
   6276                         int platformVersion = Integer.parseInt(str[0]);
   6277                         offset = extractLine(buffer, offset, str);
   6278                         info.installerPackageName = (str[0].length() > 0) ? str[0] : null;
   6279                         offset = extractLine(buffer, offset, str);
   6280                         boolean hasApk = str[0].equals("1");
   6281                         offset = extractLine(buffer, offset, str);
   6282                         int numSigs = Integer.parseInt(str[0]);
   6283                         if (numSigs > 0) {
   6284                             Signature[] sigs = new Signature[numSigs];
   6285                             for (int i = 0; i < numSigs; i++) {
   6286                                 offset = extractLine(buffer, offset, str);
   6287                                 sigs[i] = new Signature(str[0]);
   6288                             }
   6289                             mManifestSignatures.put(info.packageName, sigs);
   6290 
   6291                             // Okay, got the manifest info we need...
   6292                             try {
   6293                                 PackageInfo pkgInfo = mPackageManager.getPackageInfo(
   6294                                         info.packageName, PackageManager.GET_SIGNATURES);
   6295                                 // Fall through to IGNORE if the app explicitly disallows backup
   6296                                 final int flags = pkgInfo.applicationInfo.flags;
   6297                                 if ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0) {
   6298                                     // Restore system-uid-space packages only if they have
   6299                                     // defined a custom backup agent
   6300                                     if ((pkgInfo.applicationInfo.uid >= Process.FIRST_APPLICATION_UID)
   6301                                             || (pkgInfo.applicationInfo.backupAgentName != null)) {
   6302                                         // Verify signatures against any installed version; if they
   6303                                         // don't match, then we fall though and ignore the data.  The
   6304                                         // signatureMatch() method explicitly ignores the signature
   6305                                         // check for packages installed on the system partition, because
   6306                                         // such packages are signed with the platform cert instead of
   6307                                         // the app developer's cert, so they're different on every
   6308                                         // device.
   6309                                         if (signaturesMatch(sigs, pkgInfo)) {
   6310                                             if (pkgInfo.versionCode >= version) {
   6311                                                 Slog.i(TAG, "Sig + version match; taking data");
   6312                                                 policy = RestorePolicy.ACCEPT;
   6313                                             } else {
   6314                                                 // The data is from a newer version of the app than
   6315                                                 // is presently installed.  That means we can only
   6316                                                 // use it if the matching apk is also supplied.
   6317                                                 Slog.d(TAG, "Data version " + version
   6318                                                         + " is newer than installed version "
   6319                                                         + pkgInfo.versionCode + " - requiring apk");
   6320                                                 policy = RestorePolicy.ACCEPT_IF_APK;
   6321                                             }
   6322                                         } else {
   6323                                             Slog.w(TAG, "Restore manifest signatures do not match "
   6324                                                     + "installed application for " + info.packageName);
   6325                                         }
   6326                                     } else {
   6327                                         Slog.w(TAG, "Package " + info.packageName
   6328                                                 + " is system level with no agent");
   6329                                     }
   6330                                 } else {
   6331                                     if (DEBUG) Slog.i(TAG, "Restore manifest from "
   6332                                             + info.packageName + " but allowBackup=false");
   6333                                 }
   6334                             } catch (NameNotFoundException e) {
   6335                                 // Okay, the target app isn't installed.  We can process
   6336                                 // the restore properly only if the dataset provides the
   6337                                 // apk file and we can successfully install it.
   6338                                 if (DEBUG) Slog.i(TAG, "Package " + info.packageName
   6339                                         + " not installed; requiring apk in dataset");
   6340                                 policy = RestorePolicy.ACCEPT_IF_APK;
   6341                             }
   6342 
   6343                             if (policy == RestorePolicy.ACCEPT_IF_APK && !hasApk) {
   6344                                 Slog.i(TAG, "Cannot restore package " + info.packageName
   6345                                         + " without the matching .apk");
   6346                             }
   6347                         } else {
   6348                             Slog.i(TAG, "Missing signature on backed-up package "
   6349                                     + info.packageName);
   6350                         }
   6351                     } else {
   6352                         Slog.i(TAG, "Expected package " + info.packageName
   6353                                 + " but restore manifest claims " + manifestPackage);
   6354                     }
   6355                 } else {
   6356                     Slog.i(TAG, "Unknown restore manifest version " + version
   6357                             + " for package " + info.packageName);
   6358                 }
   6359             } catch (NumberFormatException e) {
   6360                 Slog.w(TAG, "Corrupt restore manifest for package " + info.packageName);
   6361             } catch (IllegalArgumentException e) {
   6362                 Slog.w(TAG, e.getMessage());
   6363             }
   6364 
   6365             return policy;
   6366         }
   6367 
   6368         // Builds a line from a byte buffer starting at 'offset', and returns
   6369         // the index of the next unconsumed data in the buffer.
   6370         int extractLine(byte[] buffer, int offset, String[] outStr) throws IOException {
   6371             final int end = buffer.length;
   6372             if (offset >= end) throw new IOException("Incomplete data");
   6373 
   6374             int pos;
   6375             for (pos = offset; pos < end; pos++) {
   6376                 byte c = buffer[pos];
   6377                 // at LF we declare end of line, and return the next char as the
   6378                 // starting point for the next time through
   6379                 if (c == '\n') {
   6380                     break;
   6381                 }
   6382             }
   6383             outStr[0] = new String(buffer, offset, pos - offset);
   6384             pos++;  // may be pointing an extra byte past the end but that's okay
   6385             return pos;
   6386         }
   6387 
   6388         void dumpFileMetadata(FileMetadata info) {
   6389             if (DEBUG) {
   6390                 StringBuilder b = new StringBuilder(128);
   6391 
   6392                 // mode string
   6393                 b.append((info.type == BackupAgent.TYPE_DIRECTORY) ? 'd' : '-');
   6394                 b.append(((info.mode & 0400) != 0) ? 'r' : '-');
   6395                 b.append(((info.mode & 0200) != 0) ? 'w' : '-');
   6396                 b.append(((info.mode & 0100) != 0) ? 'x' : '-');
   6397                 b.append(((info.mode & 0040) != 0) ? 'r' : '-');
   6398                 b.append(((info.mode & 0020) != 0) ? 'w' : '-');
   6399                 b.append(((info.mode & 0010) != 0) ? 'x' : '-');
   6400                 b.append(((info.mode & 0004) != 0) ? 'r' : '-');
   6401                 b.append(((info.mode & 0002) != 0) ? 'w' : '-');
   6402                 b.append(((info.mode & 0001) != 0) ? 'x' : '-');
   6403                 b.append(String.format(" %9d ", info.size));
   6404 
   6405                 Date stamp = new Date(info.mtime);
   6406                 b.append(new SimpleDateFormat("MMM dd HH:mm:ss ").format(stamp));
   6407 
   6408                 b.append(info.packageName);
   6409                 b.append(" :: ");
   6410                 b.append(info.domain);
   6411                 b.append(" :: ");
   6412                 b.append(info.path);
   6413 
   6414                 Slog.i(TAG, b.toString());
   6415             }
   6416         }
   6417         // Consume a tar file header block [sequence] and accumulate the relevant metadata
   6418         FileMetadata readTarHeaders(InputStream instream) throws IOException {
   6419             byte[] block = new byte[512];
   6420             FileMetadata info = null;
   6421 
   6422             boolean gotHeader = readTarHeader(instream, block);
   6423             if (gotHeader) {
   6424                 try {
   6425                     // okay, presume we're okay, and extract the various metadata
   6426                     info = new FileMetadata();
   6427                     info.size = extractRadix(block, 124, 12, 8);
   6428                     info.mtime = extractRadix(block, 136, 12, 8);
   6429                     info.mode = extractRadix(block, 100, 8, 8);
   6430 
   6431                     info.path = extractString(block, 345, 155); // prefix
   6432                     String path = extractString(block, 0, 100);
   6433                     if (path.length() > 0) {
   6434                         if (info.path.length() > 0) info.path += '/';
   6435                         info.path += path;
   6436                     }
   6437 
   6438                     // tar link indicator field: 1 byte at offset 156 in the header.
   6439                     int typeChar = block[156];
   6440                     if (typeChar == 'x') {
   6441                         // pax extended header, so we need to read that
   6442                         gotHeader = readPaxExtendedHeader(instream, info);
   6443                         if (gotHeader) {
   6444                             // and after a pax extended header comes another real header -- read
   6445                             // that to find the real file type
   6446                             gotHeader = readTarHeader(instream, block);
   6447                         }
   6448                         if (!gotHeader) throw new IOException("Bad or missing pax header");
   6449 
   6450                         typeChar = block[156];
   6451                     }
   6452 
   6453                     switch (typeChar) {
   6454                         case '0': info.type = BackupAgent.TYPE_FILE; break;
   6455                         case '5': {
   6456                             info.type = BackupAgent.TYPE_DIRECTORY;
   6457                             if (info.size != 0) {
   6458                                 Slog.w(TAG, "Directory entry with nonzero size in header");
   6459                                 info.size = 0;
   6460                             }
   6461                             break;
   6462                         }
   6463                         case 0: {
   6464                             // presume EOF
   6465                             if (DEBUG) Slog.w(TAG, "Saw type=0 in tar header block, info=" + info);
   6466                             return null;
   6467                         }
   6468                         default: {
   6469                             Slog.e(TAG, "Unknown tar entity type: " + typeChar);
   6470                             throw new IOException("Unknown entity type " + typeChar);
   6471                         }
   6472                     }
   6473 
   6474                     // Parse out the path
   6475                     //
   6476                     // first: apps/shared/unrecognized
   6477                     if (FullBackup.SHARED_PREFIX.regionMatches(0,
   6478                             info.path, 0, FullBackup.SHARED_PREFIX.length())) {
   6479                         // File in shared storage.  !!! TODO: implement this.
   6480                         info.path = info.path.substring(FullBackup.SHARED_PREFIX.length());
   6481                         info.packageName = SHARED_BACKUP_AGENT_PACKAGE;
   6482                         info.domain = FullBackup.SHARED_STORAGE_TOKEN;
   6483                         if (DEBUG) Slog.i(TAG, "File in shared storage: " + info.path);
   6484                     } else if (FullBackup.APPS_PREFIX.regionMatches(0,
   6485                             info.path, 0, FullBackup.APPS_PREFIX.length())) {
   6486                         // App content!  Parse out the package name and domain
   6487 
   6488                         // strip the apps/ prefix
   6489                         info.path = info.path.substring(FullBackup.APPS_PREFIX.length());
   6490 
   6491                         // extract the package name
   6492                         int slash = info.path.indexOf('/');
   6493                         if (slash < 0) throw new IOException("Illegal semantic path in " + info.path);
   6494                         info.packageName = info.path.substring(0, slash);
   6495                         info.path = info.path.substring(slash+1);
   6496 
   6497                         // if it's a manifest or metadata payload we're done, otherwise parse
   6498                         // out the domain into which the file will be restored
   6499                         if (!info.path.equals(BACKUP_MANIFEST_FILENAME)
   6500                                 && !info.path.equals(BACKUP_METADATA_FILENAME)) {
   6501                             slash = info.path.indexOf('/');
   6502                             if (slash < 0) throw new IOException("Illegal semantic path in non-manifest " + info.path);
   6503                             info.domain = info.path.substring(0, slash);
   6504                             info.path = info.path.substring(slash + 1);
   6505                         }
   6506                     }
   6507                 } catch (IOException e) {
   6508                     if (DEBUG) {
   6509                         Slog.e(TAG, "Parse error in header: " + e.getMessage());
   6510                         HEXLOG(block);
   6511                     }
   6512                     throw e;
   6513                 }
   6514             }
   6515             return info;
   6516         }
   6517 
   6518         private void HEXLOG(byte[] block) {
   6519             int offset = 0;
   6520             int todo = block.length;
   6521             StringBuilder buf = new StringBuilder(64);
   6522             while (todo > 0) {
   6523                 buf.append(String.format("%04x   ", offset));
   6524                 int numThisLine = (todo > 16) ? 16 : todo;
   6525                 for (int i = 0; i < numThisLine; i++) {
   6526                     buf.append(String.format("%02x ", block[offset+i]));
   6527                 }
   6528                 Slog.i("hexdump", buf.toString());
   6529                 buf.setLength(0);
   6530                 todo -= numThisLine;
   6531                 offset += numThisLine;
   6532             }
   6533         }
   6534 
   6535         // Read exactly the given number of bytes into a buffer at the stated offset.
   6536         // Returns false if EOF is encountered before the requested number of bytes
   6537         // could be read.
   6538         int readExactly(InputStream in, byte[] buffer, int offset, int size)
   6539                 throws IOException {
   6540             if (size <= 0) throw new IllegalArgumentException("size must be > 0");
   6541 
   6542             int soFar = 0;
   6543             while (soFar < size) {
   6544                 int nRead = in.read(buffer, offset + soFar, size - soFar);
   6545                 if (nRead <= 0) {
   6546                     if (MORE_DEBUG) Slog.w(TAG, "- wanted exactly " + size + " but got only " + soFar);
   6547                     break;
   6548                 }
   6549                 soFar += nRead;
   6550             }
   6551             return soFar;
   6552         }
   6553 
   6554         boolean readTarHeader(InputStream instream, byte[] block) throws IOException {
   6555             final int got = readExactly(instream, block, 0, 512);
   6556             if (got == 0) return false;     // Clean EOF
   6557             if (got < 512) throw new IOException("Unable to read full block header");
   6558             mBytes += 512;
   6559             return true;
   6560         }
   6561 
   6562         // overwrites 'info' fields based on the pax extended header
   6563         boolean readPaxExtendedHeader(InputStream instream, FileMetadata info)
   6564                 throws IOException {
   6565             // We should never see a pax extended header larger than this
   6566             if (info.size > 32*1024) {
   6567                 Slog.w(TAG, "Suspiciously large pax header size " + info.size
   6568                         + " - aborting");
   6569                 throw new IOException("Sanity failure: pax header size " + info.size);
   6570             }
   6571 
   6572             // read whole blocks, not just the content size
   6573             int numBlocks = (int)((info.size + 511) >> 9);
   6574             byte[] data = new byte[numBlocks * 512];
   6575             if (readExactly(instream, data, 0, data.length) < data.length) {
   6576                 throw new IOException("Unable to read full pax header");
   6577             }
   6578             mBytes += data.length;
   6579 
   6580             final int contentSize = (int) info.size;
   6581             int offset = 0;
   6582             do {
   6583                 // extract the line at 'offset'
   6584                 int eol = offset+1;
   6585                 while (eol < contentSize && data[eol] != ' ') eol++;
   6586                 if (eol >= contentSize) {
   6587                     // error: we just hit EOD looking for the end of the size field
   6588                     throw new IOException("Invalid pax data");
   6589                 }
   6590                 // eol points to the space between the count and the key
   6591                 int linelen = (int) extractRadix(data, offset, eol - offset, 10);
   6592                 int key = eol + 1;  // start of key=value
   6593                 eol = offset + linelen - 1; // trailing LF
   6594                 int value;
   6595                 for (value = key+1; data[value] != '=' && value <= eol; value++);
   6596                 if (value > eol) {
   6597                     throw new IOException("Invalid pax declaration");
   6598                 }
   6599 
   6600                 // pax requires that key/value strings be in UTF-8
   6601                 String keyStr = new String(data, key, value-key, "UTF-8");
   6602                 // -1 to strip the trailing LF
   6603                 String valStr = new String(data, value+1, eol-value-1, "UTF-8");
   6604 
   6605                 if ("path".equals(keyStr)) {
   6606                     info.path = valStr;
   6607                 } else if ("size".equals(keyStr)) {
   6608                     info.size = Long.parseLong(valStr);
   6609                 } else {
   6610                     if (DEBUG) Slog.i(TAG, "Unhandled pax key: " + key);
   6611                 }
   6612 
   6613                 offset += linelen;
   6614             } while (offset < contentSize);
   6615 
   6616             return true;
   6617         }
   6618 
   6619         long extractRadix(byte[] data, int offset, int maxChars, int radix)
   6620                 throws IOException {
   6621             long value = 0;
   6622             final int end = offset + maxChars;
   6623             for (int i = offset; i < end; i++) {
   6624                 final byte b = data[i];
   6625                 // Numeric fields in tar can terminate with either NUL or SPC
   6626                 if (b == 0 || b == ' ') break;
   6627                 if (b < '0' || b > ('0' + radix - 1)) {
   6628                     throw new IOException("Invalid number in header: '" + (char)b + "' for radix " + radix);
   6629                 }
   6630                 value = radix * value + (b - '0');
   6631             }
   6632             return value;
   6633         }
   6634 
   6635         String extractString(byte[] data, int offset, int maxChars) throws IOException {
   6636             final int end = offset + maxChars;
   6637             int eos = offset;
   6638             // tar string fields terminate early with a NUL
   6639             while (eos < end && data[eos] != 0) eos++;
   6640             return new String(data, offset, eos-offset, "US-ASCII");
   6641         }
   6642 
   6643         void sendStartRestore() {
   6644             if (mObserver != null) {
   6645                 try {
   6646                     mObserver.onStartRestore();
   6647                 } catch (RemoteException e) {
   6648                     Slog.w(TAG, "full restore observer went away: startRestore");
   6649                     mObserver = null;
   6650                 }
   6651             }
   6652         }
   6653 
   6654         void sendOnRestorePackage(String name) {
   6655             if (mObserver != null) {
   6656                 try {
   6657                     // TODO: use a more user-friendly name string
   6658                     mObserver.onRestorePackage(name);
   6659                 } catch (RemoteException e) {
   6660                     Slog.w(TAG, "full restore observer went away: restorePackage");
   6661                     mObserver = null;
   6662                 }
   6663             }
   6664         }
   6665 
   6666         void sendEndRestore() {
   6667             if (mObserver != null) {
   6668                 try {
   6669                     mObserver.onEndRestore();
   6670                 } catch (RemoteException e) {
   6671                     Slog.w(TAG, "full restore observer went away: endRestore");
   6672                     mObserver = null;
   6673                 }
   6674             }
   6675         }
   6676     }
   6677 
   6678     // ----- Restore handling -----
   6679 
   6680     // new style: we only store the SHA-1 hashes of each sig, not the full block
   6681     static boolean signaturesMatch(ArrayList<byte[]> storedSigHashes, PackageInfo target) {
   6682         if (target == null) {
   6683             return false;
   6684         }
   6685 
   6686         // If the target resides on the system partition, we allow it to restore
   6687         // data from the like-named package in a restore set even if the signatures
   6688         // do not match.  (Unlike general applications, those flashed to the system
   6689         // partition will be signed with the device's platform certificate, so on
   6690         // different phones the same system app will have different signatures.)
   6691         if ((target.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
   6692             if (DEBUG) Slog.v(TAG, "System app " + target.packageName + " - skipping sig check");
   6693             return true;
   6694         }
   6695 
   6696         // Allow unsigned apps, but not signed on one device and unsigned on the other
   6697         // !!! TODO: is this the right policy?
   6698         Signature[] deviceSigs = target.signatures;
   6699         if (MORE_DEBUG) Slog.v(TAG, "signaturesMatch(): stored=" + storedSigHashes
   6700                 + " device=" + deviceSigs);
   6701         if ((storedSigHashes == null || storedSigHashes.size() == 0)
   6702                 && (deviceSigs == null || deviceSigs.length == 0)) {
   6703             return true;
   6704         }
   6705         if (storedSigHashes == null || deviceSigs == null) {
   6706             return false;
   6707         }
   6708 
   6709         // !!! TODO: this demands that every stored signature match one
   6710         // that is present on device, and does not demand the converse.
   6711         // Is this this right policy?
   6712         final int nStored = storedSigHashes.size();
   6713         final int nDevice = deviceSigs.length;
   6714 
   6715         // hash each on-device signature
   6716         ArrayList<byte[]> deviceHashes = new ArrayList<byte[]>(nDevice);
   6717         for (int i = 0; i < nDevice; i++) {
   6718             deviceHashes.add(hashSignature(deviceSigs[i]));
   6719         }
   6720 
   6721         // now ensure that each stored sig (hash) matches an on-device sig (hash)
   6722         for (int n = 0; n < nStored; n++) {
   6723             boolean match = false;
   6724             final byte[] storedHash = storedSigHashes.get(n);
   6725             for (int i = 0; i < nDevice; i++) {
   6726                 if (Arrays.equals(storedHash, deviceHashes.get(i))) {
   6727                     match = true;
   6728                     break;
   6729                 }
   6730             }
   6731             // match is false when no on-device sig matched one of the stored ones
   6732             if (!match) {
   6733                 return false;
   6734             }
   6735         }
   6736 
   6737         return true;
   6738     }
   6739 
   6740     static byte[] hashSignature(Signature sig) {
   6741         try {
   6742             MessageDigest digest = MessageDigest.getInstance("SHA-256");
   6743             digest.update(sig.toByteArray());
   6744             return digest.digest();
   6745         } catch (NoSuchAlgorithmException e) {
   6746             Slog.w(TAG, "No SHA-256 algorithm found!");
   6747         }
   6748         return null;
   6749     }
   6750 
   6751     // Old style: directly match the stored vs on device signature blocks
   6752     static boolean signaturesMatch(Signature[] storedSigs, PackageInfo target) {
   6753         if (target == null) {
   6754             return false;
   6755         }
   6756 
   6757         // If the target resides on the system partition, we allow it to restore
   6758         // data from the like-named package in a restore set even if the signatures
   6759         // do not match.  (Unlike general applications, those flashed to the system
   6760         // partition will be signed with the device's platform certificate, so on
   6761         // different phones the same system app will have different signatures.)
   6762         if ((target.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
   6763             if (DEBUG) Slog.v(TAG, "System app " + target.packageName + " - skipping sig check");
   6764             return true;
   6765         }
   6766 
   6767         // Allow unsigned apps, but not signed on one device and unsigned on the other
   6768         // !!! TODO: is this the right policy?
   6769         Signature[] deviceSigs = target.signatures;
   6770         if (MORE_DEBUG) Slog.v(TAG, "signaturesMatch(): stored=" + storedSigs
   6771                 + " device=" + deviceSigs);
   6772         if ((storedSigs == null || storedSigs.length == 0)
   6773                 && (deviceSigs == null || deviceSigs.length == 0)) {
   6774             return true;
   6775         }
   6776         if (storedSigs == null || deviceSigs == null) {
   6777             return false;
   6778         }
   6779 
   6780         // !!! TODO: this demands that every stored signature match one
   6781         // that is present on device, and does not demand the converse.
   6782         // Is this this right policy?
   6783         int nStored = storedSigs.length;
   6784         int nDevice = deviceSigs.length;
   6785 
   6786         for (int i=0; i < nStored; i++) {
   6787             boolean match = false;
   6788             for (int j=0; j < nDevice; j++) {
   6789                 if (storedSigs[i].equals(deviceSigs[j])) {
   6790                     match = true;
   6791                     break;
   6792                 }
   6793             }
   6794             if (!match) {
   6795                 return false;
   6796             }
   6797         }
   6798         return true;
   6799     }
   6800 
   6801     // Used by both incremental and full restore
   6802     void restoreWidgetData(String packageName, byte[] widgetData) {
   6803         // Apply the restored widget state and generate the ID update for the app
   6804         AppWidgetBackupBridge.restoreWidgetState(packageName, widgetData, UserHandle.USER_OWNER);
   6805     }
   6806 
   6807     // *****************************
   6808     // NEW UNIFIED RESTORE IMPLEMENTATION
   6809     // *****************************
   6810 
   6811     // states of the unified-restore state machine
   6812     enum UnifiedRestoreState {
   6813         INITIAL,
   6814         RUNNING_QUEUE,
   6815         RESTORE_KEYVALUE,
   6816         RESTORE_FULL,
   6817         RESTORE_FINISHED,
   6818         FINAL
   6819     }
   6820 
   6821     class PerformUnifiedRestoreTask implements BackupRestoreTask {
   6822         // Transport we're working with to do the restore
   6823         private IBackupTransport mTransport;
   6824 
   6825         // Where per-transport saved state goes
   6826         File mStateDir;
   6827 
   6828         // Restore observer; may be null
   6829         private IRestoreObserver mObserver;
   6830 
   6831         // Token identifying the dataset to the transport
   6832         private long mToken;
   6833 
   6834         // When this is a restore-during-install, this is the token identifying the
   6835         // operation to the Package Manager, and we must ensure that we let it know
   6836         // when we're finished.
   6837         private int mPmToken;
   6838 
   6839         // Is this a whole-system restore, i.e. are we establishing a new ancestral
   6840         // dataset to base future restore-at-install operations from?
   6841         private boolean mIsSystemRestore;
   6842 
   6843         // If this is a single-package restore, what package are we interested in?
   6844         private PackageInfo mTargetPackage;
   6845 
   6846         // In all cases, the calculated list of packages that we are trying to restore
   6847         private List<PackageInfo> mAcceptSet;
   6848 
   6849         // Our bookkeeping about the ancestral dataset
   6850         private PackageManagerBackupAgent mPmAgent;
   6851 
   6852         // Currently-bound backup agent for restore + restoreFinished purposes
   6853         private IBackupAgent mAgent;
   6854 
   6855         // What sort of restore we're doing now
   6856         private RestoreDescription mRestoreDescription;
   6857 
   6858         // The package we're currently restoring
   6859         private PackageInfo mCurrentPackage;
   6860 
   6861         // Widget-related data handled as part of this restore operation
   6862         private byte[] mWidgetData;
   6863 
   6864         // Number of apps restored in this pass
   6865         private int mCount;
   6866 
   6867         // When did we start?
   6868         private long mStartRealtime;
   6869 
   6870         // State machine progress
   6871         private UnifiedRestoreState mState;
   6872 
   6873         // How are things going?
   6874         private int mStatus;
   6875 
   6876         // Done?
   6877         private boolean mFinished;
   6878 
   6879         // Key/value: bookkeeping about staged data and files for agent access
   6880         private File mBackupDataName;
   6881         private File mStageName;
   6882         private File mSavedStateName;
   6883         private File mNewStateName;
   6884         ParcelFileDescriptor mBackupData;
   6885         ParcelFileDescriptor mNewState;
   6886 
   6887         // Invariant: mWakelock is already held, and this task is responsible for
   6888         // releasing it at the end of the restore operation.
   6889         PerformUnifiedRestoreTask(IBackupTransport transport, IRestoreObserver observer,
   6890                 long restoreSetToken, PackageInfo targetPackage, int pmToken,
   6891                 boolean isFullSystemRestore, String[] filterSet) {
   6892             mState = UnifiedRestoreState.INITIAL;
   6893             mStartRealtime = SystemClock.elapsedRealtime();
   6894 
   6895             mTransport = transport;
   6896             mObserver = observer;
   6897             mToken = restoreSetToken;
   6898             mPmToken = pmToken;
   6899             mTargetPackage = targetPackage;
   6900             mIsSystemRestore = isFullSystemRestore;
   6901             mFinished = false;
   6902 
   6903             if (targetPackage != null) {
   6904                 // Single package restore
   6905                 mAcceptSet = new ArrayList<PackageInfo>();
   6906                 mAcceptSet.add(targetPackage);
   6907             } else {
   6908                 // Everything possible, or a target set
   6909                 if (filterSet == null) {
   6910                     // We want everything and a pony
   6911                     List<PackageInfo> apps =
   6912                             PackageManagerBackupAgent.getStorableApplications(mPackageManager);
   6913                     filterSet = packagesToNames(apps);
   6914                     if (DEBUG) {
   6915                         Slog.i(TAG, "Full restore; asking for " + filterSet.length + " apps");
   6916                     }
   6917                 }
   6918 
   6919                 mAcceptSet = new ArrayList<PackageInfo>(filterSet.length);
   6920 
   6921                 // Pro tem, we insist on moving the settings provider package to last place.
   6922                 // Keep track of whether it's in the list, and bump it down if so.  We also
   6923                 // want to do the system package itself first if it's called for.
   6924                 boolean hasSystem = false;
   6925                 boolean hasSettings = false;
   6926                 for (int i = 0; i < filterSet.length; i++) {
   6927                     try {
   6928                         PackageInfo info = mPackageManager.getPackageInfo(filterSet[i], 0);
   6929                         if ("android".equals(info.packageName)) {
   6930                             hasSystem = true;
   6931                             continue;
   6932                         }
   6933                         if (SETTINGS_PACKAGE.equals(info.packageName)) {
   6934                             hasSettings = true;
   6935                             continue;
   6936                         }
   6937 
   6938                         if (appIsEligibleForBackup(info.applicationInfo)) {
   6939                             mAcceptSet.add(info);
   6940                         }
   6941                     } catch (NameNotFoundException e) {
   6942                         // requested package name doesn't exist; ignore it
   6943                     }
   6944                 }
   6945                 if (hasSystem) {
   6946                     try {
   6947                         mAcceptSet.add(0, mPackageManager.getPackageInfo("android", 0));
   6948                     } catch (NameNotFoundException e) {
   6949                         // won't happen; we know a priori that it's valid
   6950                     }
   6951                 }
   6952                 if (hasSettings) {
   6953                     try {
   6954                         mAcceptSet.add(mPackageManager.getPackageInfo(SETTINGS_PACKAGE, 0));
   6955                     } catch (NameNotFoundException e) {
   6956                         // this one is always valid too
   6957                     }
   6958                 }
   6959             }
   6960 
   6961             if (MORE_DEBUG) {
   6962                 Slog.v(TAG, "Restore; accept set size is " + mAcceptSet.size());
   6963                 for (PackageInfo info : mAcceptSet) {
   6964                     Slog.v(TAG, "   " + info.packageName);
   6965                 }
   6966             }
   6967         }
   6968 
   6969         private String[] packagesToNames(List<PackageInfo> apps) {
   6970             final int N = apps.size();
   6971             String[] names = new String[N];
   6972             for (int i = 0; i < N; i++) {
   6973                 names[i] = apps.get(i).packageName;
   6974             }
   6975             return names;
   6976         }
   6977 
   6978         // Execute one tick of whatever state machine the task implements
   6979         @Override
   6980         public void execute() {
   6981             if (MORE_DEBUG) Slog.v(TAG, "*** Executing restore step " + mState);
   6982             switch (mState) {
   6983                 case INITIAL:
   6984                     startRestore();
   6985                     break;
   6986 
   6987                 case RUNNING_QUEUE:
   6988                     dispatchNextRestore();
   6989                     break;
   6990 
   6991                 case RESTORE_KEYVALUE:
   6992                     restoreKeyValue();
   6993                     break;
   6994 
   6995                 case RESTORE_FULL:
   6996                     restoreFull();
   6997                     break;
   6998 
   6999                 case RESTORE_FINISHED:
   7000                     restoreFinished();
   7001                     break;
   7002 
   7003                 case FINAL:
   7004                     if (!mFinished) finalizeRestore();
   7005                     else {
   7006                         Slog.e(TAG, "Duplicate finish");
   7007                     }
   7008                     mFinished = true;
   7009                     break;
   7010             }
   7011         }
   7012 
   7013         /*
   7014          * SKETCH OF OPERATION
   7015          *
   7016          * create one of these PerformUnifiedRestoreTask objects, telling it which
   7017          * dataset & transport to address, and then parameters within the restore
   7018          * operation: single target package vs many, etc.
   7019          *
   7020          * 1. transport.startRestore(token, list-of-packages).  If we need @pm@  it is
   7021          * always placed first and the settings provider always placed last [for now].
   7022          *
   7023          * 1a [if we needed @pm@ then nextRestorePackage() and restore the PMBA inline]
   7024          *
   7025          *   [ state change => RUNNING_QUEUE ]
   7026          *
   7027          * NOW ITERATE:
   7028          *
   7029          * { 3. t.nextRestorePackage()
   7030          *   4. does the metadata for this package allow us to restore it?
   7031          *      does the on-disk app permit us to restore it? [re-check allowBackup etc]
   7032          *   5. is this a key/value dataset?  => key/value agent restore
   7033          *       [ state change => RESTORE_KEYVALUE ]
   7034          *       5a. spin up agent
   7035          *       5b. t.getRestoreData() to stage it properly
   7036          *       5c. call into agent to perform restore
   7037          *       5d. tear down agent
   7038          *       [ state change => RUNNING_QUEUE ]
   7039          *
   7040          *   6. else it's a stream dataset:
   7041          *       [ state change => RESTORE_FULL ]
   7042          *       6a. instantiate the engine for a stream restore: engine handles agent lifecycles
   7043          *       6b. spin off engine runner on separate thread
   7044          *       6c. ITERATE getNextFullRestoreDataChunk() and copy data to engine runner socket
   7045          *       [ state change => RUNNING_QUEUE ]
   7046          * }
   7047          *
   7048          *   [ state change => FINAL ]
   7049          *
   7050          * 7. t.finishRestore(), release wakelock, etc.
   7051          *
   7052          *
   7053          */
   7054 
   7055         // state INITIAL : set up for the restore and read the metadata if necessary
   7056         private  void startRestore() {
   7057             sendStartRestore(mAcceptSet.size());
   7058 
   7059             // If we're starting a full-system restore, set up to begin widget ID remapping
   7060             if (mIsSystemRestore) {
   7061                 AppWidgetBackupBridge.restoreStarting(UserHandle.USER_OWNER);
   7062             }
   7063 
   7064             try {
   7065                 String transportDir = mTransport.transportDirName();
   7066                 mStateDir = new File(mBaseStateDir, transportDir);
   7067 
   7068                 // Fetch the current metadata from the dataset first
   7069                 PackageInfo pmPackage = new PackageInfo();
   7070                 pmPackage.packageName = PACKAGE_MANAGER_SENTINEL;
   7071                 mAcceptSet.add(0, pmPackage);
   7072 
   7073                 PackageInfo[] packages = mAcceptSet.toArray(new PackageInfo[0]);
   7074                 mStatus = mTransport.startRestore(mToken, packages);
   7075                 if (mStatus != BackupTransport.TRANSPORT_OK) {
   7076                     Slog.e(TAG, "Transport error " + mStatus + "; no restore possible");
   7077                     mStatus = BackupTransport.TRANSPORT_ERROR;
   7078                     executeNextState(UnifiedRestoreState.FINAL);
   7079                     return;
   7080                 }
   7081 
   7082                 RestoreDescription desc = mTransport.nextRestorePackage();
   7083                 if (desc == null) {
   7084                     Slog.e(TAG, "No restore metadata available; halting");
   7085                     mStatus = BackupTransport.TRANSPORT_ERROR;
   7086                     executeNextState(UnifiedRestoreState.FINAL);
   7087                     return;
   7088                 }
   7089                 if (!PACKAGE_MANAGER_SENTINEL.equals(desc.getPackageName())) {
   7090                     Slog.e(TAG, "Required metadata but got " + desc.getPackageName());
   7091                     mStatus = BackupTransport.TRANSPORT_ERROR;
   7092                     executeNextState(UnifiedRestoreState.FINAL);
   7093                     return;
   7094                 }
   7095 
   7096                 // Pull the Package Manager metadata from the restore set first
   7097                 mCurrentPackage = new PackageInfo();
   7098                 mCurrentPackage.packageName = PACKAGE_MANAGER_SENTINEL;
   7099                 mPmAgent = new PackageManagerBackupAgent(mPackageManager, null);
   7100                 mAgent = IBackupAgent.Stub.asInterface(mPmAgent.onBind());
   7101                 if (MORE_DEBUG) {
   7102                     Slog.v(TAG, "initiating restore for PMBA");
   7103                 }
   7104                 initiateOneRestore(mCurrentPackage, 0);
   7105                 // The PM agent called operationComplete() already, because our invocation
   7106                 // of it is process-local and therefore synchronous.  That means that the
   7107                 // next-state message (RUNNING_QUEUE) is already enqueued.  Only if we're
   7108                 // unable to proceed with running the queue do we remove that pending
   7109                 // message and jump straight to the FINAL state.
   7110 
   7111                 // Verify that the backup set includes metadata.  If not, we can't do
   7112                 // signature/version verification etc, so we simply do not proceed with
   7113                 // the restore operation.
   7114                 if (!mPmAgent.hasMetadata()) {
   7115                     Slog.e(TAG, "No restore metadata available, so not restoring");
   7116                     EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
   7117                             PACKAGE_MANAGER_SENTINEL,
   7118                             "Package manager restore metadata missing");
   7119                     mStatus = BackupTransport.TRANSPORT_ERROR;
   7120                     mBackupHandler.removeMessages(MSG_BACKUP_RESTORE_STEP, this);
   7121                     executeNextState(UnifiedRestoreState.FINAL);
   7122                     return;
   7123                 }
   7124 
   7125                 // Success; cache the metadata and continue as expected with the
   7126                 // next state already enqueued
   7127 
   7128             } catch (RemoteException e) {
   7129                 // If we lost the transport at any time, halt
   7130                 Slog.e(TAG, "Unable to contact transport for restore");
   7131                 mStatus = BackupTransport.TRANSPORT_ERROR;
   7132                 mBackupHandler.removeMessages(MSG_BACKUP_RESTORE_STEP, this);
   7133                 executeNextState(UnifiedRestoreState.FINAL);
   7134                 return;
   7135             }
   7136         }
   7137 
   7138         // state RUNNING_QUEUE : figure out what the next thing to be restored is,
   7139         // and fire the appropriate next step
   7140         private void dispatchNextRestore() {
   7141             UnifiedRestoreState nextState = UnifiedRestoreState.FINAL;
   7142             try {
   7143                 mRestoreDescription = mTransport.nextRestorePackage();
   7144                 final String pkgName = (mRestoreDescription != null)
   7145                         ? mRestoreDescription.getPackageName() : null;
   7146                 if (pkgName == null) {
   7147                     Slog.e(TAG, "Failure getting next package name");
   7148                     EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
   7149                     nextState = UnifiedRestoreState.FINAL;
   7150                     return;
   7151                 } else if (mRestoreDescription == RestoreDescription.NO_MORE_PACKAGES) {
   7152                     // Yay we've reached the end cleanly
   7153                     if (DEBUG) {
   7154                         Slog.v(TAG, "No more packages; finishing restore");
   7155                     }
   7156                     int millis = (int) (SystemClock.elapsedRealtime() - mStartRealtime);
   7157                     EventLog.writeEvent(EventLogTags.RESTORE_SUCCESS, mCount, millis);
   7158                     nextState = UnifiedRestoreState.FINAL;
   7159                     return;
   7160                 }
   7161 
   7162                 if (DEBUG) {
   7163                     Slog.i(TAG, "Next restore package: " + mRestoreDescription);
   7164                 }
   7165                 sendOnRestorePackage(pkgName);
   7166 
   7167                 Metadata metaInfo = mPmAgent.getRestoredMetadata(pkgName);
   7168                 if (metaInfo == null) {
   7169                     Slog.e(TAG, "No metadata for " + pkgName);
   7170                     EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, pkgName,
   7171                             "Package metadata missing");
   7172                     nextState = UnifiedRestoreState.RUNNING_QUEUE;
   7173                     return;
   7174                 }
   7175 
   7176                 try {
   7177                     mCurrentPackage = mPackageManager.getPackageInfo(
   7178                             pkgName, PackageManager.GET_SIGNATURES);
   7179                 } catch (NameNotFoundException e) {
   7180                     // Whoops, we thought we could restore this package but it
   7181                     // turns out not to be present.  Skip it.
   7182                     Slog.e(TAG, "Package not present: " + pkgName);
   7183                     EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, pkgName,
   7184                             "Package missing on device");
   7185                     nextState = UnifiedRestoreState.RUNNING_QUEUE;
   7186                     return;
   7187                 }
   7188 
   7189                 if (metaInfo.versionCode > mCurrentPackage.versionCode) {
   7190                     // Data is from a "newer" version of the app than we have currently
   7191                     // installed.  If the app has not declared that it is prepared to
   7192                     // handle this case, we do not attempt the restore.
   7193                     if ((mCurrentPackage.applicationInfo.flags
   7194                             & ApplicationInfo.FLAG_RESTORE_ANY_VERSION) == 0) {
   7195                         String message = "Version " + metaInfo.versionCode
   7196                                 + " > installed version " + mCurrentPackage.versionCode;
   7197                         Slog.w(TAG, "Package " + pkgName + ": " + message);
   7198                         EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
   7199                                 pkgName, message);
   7200                         nextState = UnifiedRestoreState.RUNNING_QUEUE;
   7201                         return;
   7202                     } else {
   7203                         if (DEBUG) Slog.v(TAG, "Version " + metaInfo.versionCode
   7204                                 + " > installed " + mCurrentPackage.versionCode
   7205                                 + " but restoreAnyVersion");
   7206                     }
   7207                 }
   7208 
   7209                 if (DEBUG) Slog.v(TAG, "Package " + pkgName
   7210                         + " restore version [" + metaInfo.versionCode
   7211                         + "] is compatible with installed version ["
   7212                         + mCurrentPackage.versionCode + "]");
   7213 
   7214                 // Reset per-package preconditions and fire the appropriate next state
   7215                 mWidgetData = null;
   7216                 final int type = mRestoreDescription.getDataType();
   7217                 if (type == RestoreDescription.TYPE_KEY_VALUE) {
   7218                     nextState = UnifiedRestoreState.RESTORE_KEYVALUE;
   7219                 } else if (type == RestoreDescription.TYPE_FULL_STREAM) {
   7220                     nextState = UnifiedRestoreState.RESTORE_FULL;
   7221                 } else {
   7222                     // Unknown restore type; ignore this package and move on
   7223                     Slog.e(TAG, "Unrecognized restore type " + type);
   7224                     nextState = UnifiedRestoreState.RUNNING_QUEUE;
   7225                     return;
   7226                 }
   7227             } catch (RemoteException e) {
   7228                 Slog.e(TAG, "Can't get next target from transport; ending restore");
   7229                 EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
   7230                 nextState = UnifiedRestoreState.FINAL;
   7231                 return;
   7232             } finally {
   7233                 executeNextState(nextState);
   7234             }
   7235         }
   7236 
   7237         // state RESTORE_KEYVALUE : restore one package via key/value API set
   7238         private void restoreKeyValue() {
   7239             // Initiating the restore will pass responsibility for the state machine's
   7240             // progress to the agent callback, so we do not always execute the
   7241             // next state here.
   7242             final String packageName = mCurrentPackage.packageName;
   7243             // Validate some semantic requirements that apply in this way
   7244             // only to the key/value restore API flow
   7245             if (mCurrentPackage.applicationInfo.backupAgentName == null
   7246                     || "".equals(mCurrentPackage.applicationInfo.backupAgentName)) {
   7247                 if (DEBUG) {
   7248                     Slog.i(TAG, "Data exists for package " + packageName
   7249                             + " but app has no agent; skipping");
   7250                 }
   7251                 EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
   7252                         "Package has no agent");
   7253                 executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
   7254                 return;
   7255             }
   7256 
   7257             Metadata metaInfo = mPmAgent.getRestoredMetadata(packageName);
   7258             if (!signaturesMatch(metaInfo.sigHashes, mCurrentPackage)) {
   7259                 Slog.w(TAG, "Signature mismatch restoring " + packageName);
   7260                 EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
   7261                         "Signature mismatch");
   7262                 executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
   7263                 return;
   7264             }
   7265 
   7266             // Good to go!  Set up and bind the agent...
   7267             mAgent = bindToAgentSynchronous(
   7268                     mCurrentPackage.applicationInfo,
   7269                     IApplicationThread.BACKUP_MODE_INCREMENTAL);
   7270             if (mAgent == null) {
   7271                 Slog.w(TAG, "Can't find backup agent for " + packageName);
   7272                 EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
   7273                         "Restore agent missing");
   7274                 executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
   7275                 return;
   7276             }
   7277 
   7278             // And then finally start the restore on this agent
   7279             try {
   7280                 initiateOneRestore(mCurrentPackage, metaInfo.versionCode);
   7281                 ++mCount;
   7282             } catch (Exception e) {
   7283                 Slog.e(TAG, "Error when attempting restore: " + e.toString());
   7284                 keyValueAgentErrorCleanup();
   7285                 executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
   7286             }
   7287         }
   7288 
   7289         // Guts of a key/value restore operation
   7290         void initiateOneRestore(PackageInfo app, int appVersionCode) {
   7291             final String packageName = app.packageName;
   7292 
   7293             if (DEBUG) Slog.d(TAG, "initiateOneRestore packageName=" + packageName);
   7294 
   7295             // !!! TODO: get the dirs from the transport
   7296             mBackupDataName = new File(mDataDir, packageName + ".restore");
   7297             mStageName = new File(mDataDir, packageName + ".stage");
   7298             mNewStateName = new File(mStateDir, packageName + ".new");
   7299             mSavedStateName = new File(mStateDir, packageName);
   7300 
   7301             // don't stage the 'android' package where the wallpaper data lives.  this is
   7302             // an optimization: we know there's no widget data hosted/published by that
   7303             // package, and this way we avoid doing a spurious copy of MB-sized wallpaper
   7304             // data following the download.
   7305             boolean staging = !packageName.equals("android");
   7306             ParcelFileDescriptor stage;
   7307             File downloadFile = (staging) ? mStageName : mBackupDataName;
   7308 
   7309             final int token = generateToken();
   7310             try {
   7311                 // Run the transport's restore pass
   7312                 stage = ParcelFileDescriptor.open(downloadFile,
   7313                         ParcelFileDescriptor.MODE_READ_WRITE |
   7314                         ParcelFileDescriptor.MODE_CREATE |
   7315                         ParcelFileDescriptor.MODE_TRUNCATE);
   7316 
   7317                 if (!SELinux.restorecon(mBackupDataName)) {
   7318                     Slog.e(TAG, "SElinux restorecon failed for " + downloadFile);
   7319                 }
   7320 
   7321                 if (mTransport.getRestoreData(stage) != BackupTransport.TRANSPORT_OK) {
   7322                     // Transport-level failure, so we wind everything up and
   7323                     // terminate the restore operation.
   7324                     Slog.e(TAG, "Error getting restore data for " + packageName);
   7325                     EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
   7326                     stage.close();
   7327                     downloadFile.delete();
   7328                     executeNextState(UnifiedRestoreState.FINAL);
   7329                     return;
   7330                 }
   7331 
   7332                 // We have the data from the transport. Now we extract and strip
   7333                 // any per-package metadata (typically widget-related information)
   7334                 // if appropriate
   7335                 if (staging) {
   7336                     stage.close();
   7337                     stage = ParcelFileDescriptor.open(downloadFile,
   7338                             ParcelFileDescriptor.MODE_READ_ONLY);
   7339 
   7340                     mBackupData = ParcelFileDescriptor.open(mBackupDataName,
   7341                             ParcelFileDescriptor.MODE_READ_WRITE |
   7342                             ParcelFileDescriptor.MODE_CREATE |
   7343                             ParcelFileDescriptor.MODE_TRUNCATE);
   7344 
   7345                     BackupDataInput in = new BackupDataInput(stage.getFileDescriptor());
   7346                     BackupDataOutput out = new BackupDataOutput(mBackupData.getFileDescriptor());
   7347                     byte[] buffer = new byte[8192]; // will grow when needed
   7348                     while (in.readNextHeader()) {
   7349                         final String key = in.getKey();
   7350                         final int size = in.getDataSize();
   7351 
   7352                         // is this a special key?
   7353                         if (key.equals(KEY_WIDGET_STATE)) {
   7354                             if (DEBUG) {
   7355                                 Slog.i(TAG, "Restoring widget state for " + packageName);
   7356                             }
   7357                             mWidgetData = new byte[size];
   7358                             in.readEntityData(mWidgetData, 0, size);
   7359                         } else {
   7360                             if (size > buffer.length) {
   7361                                 buffer = new byte[size];
   7362                             }
   7363                             in.readEntityData(buffer, 0, size);
   7364                             out.writeEntityHeader(key, size);
   7365                             out.writeEntityData(buffer, size);
   7366                         }
   7367                     }
   7368 
   7369                     mBackupData.close();
   7370                 }
   7371 
   7372                 // Okay, we have the data.  Now have the agent do the restore.
   7373                 stage.close();
   7374                 mBackupData = ParcelFileDescriptor.open(mBackupDataName,
   7375                         ParcelFileDescriptor.MODE_READ_ONLY);
   7376 
   7377                 mNewState = ParcelFileDescriptor.open(mNewStateName,
   7378                         ParcelFileDescriptor.MODE_READ_WRITE |
   7379                         ParcelFileDescriptor.MODE_CREATE |
   7380                         ParcelFileDescriptor.MODE_TRUNCATE);
   7381 
   7382                 // Kick off the restore, checking for hung agents.  The timeout or
   7383                 // the operationComplete() callback will schedule the next step,
   7384                 // so we do not do that here.
   7385                 prepareOperationTimeout(token, TIMEOUT_RESTORE_INTERVAL, this);
   7386                 mAgent.doRestore(mBackupData, appVersionCode, mNewState,
   7387                         token, mBackupManagerBinder);
   7388             } catch (Exception e) {
   7389                 Slog.e(TAG, "Unable to call app for restore: " + packageName, e);
   7390                 EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
   7391                         packageName, e.toString());
   7392                 keyValueAgentErrorCleanup();    // clears any pending timeout messages as well
   7393 
   7394                 // After a restore failure we go back to running the queue.  If there
   7395                 // are no more packages to be restored that will be handled by the
   7396                 // next step.
   7397                 executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
   7398             }
   7399         }
   7400 
   7401         // state RESTORE_FULL : restore one package via streaming engine
   7402         private void restoreFull() {
   7403             // None of this can run on the work looper here, so we spin asynchronous
   7404             // work like this:
   7405             //
   7406             //   StreamFeederThread: read data from mTransport.getNextFullRestoreDataChunk()
   7407             //                       write it into the pipe to the engine
   7408             //   EngineThread: FullRestoreEngine thread communicating with the target app
   7409             //
   7410             // When finished, StreamFeederThread executes next state as appropriate on the
   7411             // backup looper, and the overall unified restore task resumes
   7412             try {
   7413                 StreamFeederThread feeder = new StreamFeederThread();
   7414                 if (DEBUG) {
   7415                     Slog.i(TAG, "Spinning threads for stream restore of "
   7416                             + mCurrentPackage.packageName);
   7417                 }
   7418                 new Thread(feeder, "unified-stream-feeder").start();
   7419 
   7420                 // At this point the feeder is responsible for advancing the restore
   7421                 // state, so we're done here.
   7422             } catch (IOException e) {
   7423                 // Unable to instantiate the feeder thread -- we need to bail on the
   7424                 // current target.  We haven't asked the transport for data yet, though,
   7425                 // so we can do that simply by going back to running the restore queue.
   7426                 Slog.e(TAG, "Unable to construct pipes for stream restore!");
   7427                 executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
   7428             }
   7429         }
   7430 
   7431         // state RESTORE_FINISHED : provide the "no more data" signpost callback at the end
   7432         private void restoreFinished() {
   7433             try {
   7434                 final int token = generateToken();
   7435                 prepareOperationTimeout(token, TIMEOUT_RESTORE_FINISHED_INTERVAL, this);
   7436                 mAgent.doRestoreFinished(token, mBackupManagerBinder);
   7437                 // If we get this far, the callback or timeout will schedule the
   7438                 // next restore state, so we're done
   7439             } catch (Exception e) {
   7440                 Slog.e(TAG, "Unable to finalize restore of " + mCurrentPackage.packageName);
   7441                 executeNextState(UnifiedRestoreState.FINAL);
   7442             }
   7443         }
   7444 
   7445         class StreamFeederThread extends RestoreEngine implements Runnable {
   7446             final String TAG = "StreamFeederThread";
   7447             FullRestoreEngine mEngine;
   7448 
   7449             // pipe through which we read data from the transport. [0] read, [1] write
   7450             ParcelFileDescriptor[] mTransportPipes;
   7451 
   7452             // pipe through which the engine will read data.  [0] read, [1] write
   7453             ParcelFileDescriptor[] mEnginePipes;
   7454 
   7455             public StreamFeederThread() throws IOException {
   7456                 mTransportPipes = ParcelFileDescriptor.createPipe();
   7457                 mEnginePipes = ParcelFileDescriptor.createPipe();
   7458                 setRunning(true);
   7459             }
   7460 
   7461             @Override
   7462             public void run() {
   7463                 UnifiedRestoreState nextState = UnifiedRestoreState.RUNNING_QUEUE;
   7464                 int status = BackupTransport.TRANSPORT_OK;
   7465 
   7466                 EventLog.writeEvent(EventLogTags.FULL_RESTORE_PACKAGE,
   7467                         mCurrentPackage.packageName);
   7468 
   7469                 mEngine = new FullRestoreEngine(null, mCurrentPackage, false, false);
   7470                 EngineThread eThread = new EngineThread(mEngine, mEnginePipes[0]);
   7471 
   7472                 ParcelFileDescriptor eWriteEnd = mEnginePipes[1];
   7473                 ParcelFileDescriptor tReadEnd = mTransportPipes[0];
   7474                 ParcelFileDescriptor tWriteEnd = mTransportPipes[1];
   7475 
   7476                 int bufferSize = 32 * 1024;
   7477                 byte[] buffer = new byte[bufferSize];
   7478                 FileOutputStream engineOut = new FileOutputStream(eWriteEnd.getFileDescriptor());
   7479                 FileInputStream transportIn = new FileInputStream(tReadEnd.getFileDescriptor());
   7480 
   7481                 // spin up the engine and start moving data to it
   7482                 new Thread(eThread, "unified-restore-engine").start();
   7483 
   7484                 try {
   7485                     while (status == BackupTransport.TRANSPORT_OK) {
   7486                         // have the transport write some of the restoring data to us
   7487                         int result = mTransport.getNextFullRestoreDataChunk(tWriteEnd);
   7488                         if (result > 0) {
   7489                             // The transport wrote this many bytes of restore data to the
   7490                             // pipe, so pass it along to the engine.
   7491                             if (MORE_DEBUG) {
   7492                                 Slog.v(TAG, "  <- transport provided chunk size " + result);
   7493                             }
   7494                             if (result > bufferSize) {
   7495                                 bufferSize = result;
   7496                                 buffer = new byte[bufferSize];
   7497                             }
   7498                             int toCopy = result;
   7499                             while (toCopy > 0) {
   7500                                 int n = transportIn.read(buffer, 0, toCopy);
   7501                                 engineOut.write(buffer, 0, n);
   7502                                 toCopy -= n;
   7503                                 if (MORE_DEBUG) {
   7504                                     Slog.v(TAG, "  -> wrote " + n + " to engine, left=" + toCopy);
   7505                                 }
   7506                             }
   7507                         } else if (result == BackupTransport.NO_MORE_DATA) {
   7508                             // Clean finish.  Wind up and we're done!
   7509                             if (MORE_DEBUG) {
   7510                                 Slog.i(TAG, "Got clean full-restore EOF for "
   7511                                         + mCurrentPackage.packageName);
   7512                             }
   7513                             status = BackupTransport.TRANSPORT_OK;
   7514                             break;
   7515                         } else {
   7516                             // Transport reported some sort of failure; the fall-through
   7517                             // handling will deal properly with that.
   7518                             Slog.e(TAG, "Error " + result + " streaming restore for "
   7519                                     + mCurrentPackage.packageName);
   7520                             EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
   7521                             status = result;
   7522                         }
   7523                     }
   7524                     if (MORE_DEBUG) Slog.v(TAG, "Done copying to engine, falling through");
   7525                 } catch (IOException e) {
   7526                     // We lost our ability to communicate via the pipes.  That's worrying
   7527                     // but potentially recoverable; abandon this package's restore but
   7528                     // carry on with the next restore target.
   7529                     Slog.e(TAG, "Unable to route data for restore");
   7530                     EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
   7531                             mCurrentPackage.packageName, "I/O error on pipes");
   7532                     status = BackupTransport.AGENT_ERROR;
   7533                 } catch (RemoteException e) {
   7534                     // The transport went away; terminate the whole operation.  Closing
   7535                     // the sockets will wake up the engine and it will then tidy up the
   7536                     // remote end.
   7537                     Slog.e(TAG, "Transport failed during restore");
   7538                     EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
   7539                     status = BackupTransport.TRANSPORT_ERROR;
   7540                 } finally {
   7541                     // Close the transport pipes and *our* end of the engine pipe,
   7542                     // but leave the engine thread's end open so that it properly
   7543                     // hits EOF and winds up its operations.
   7544                     IoUtils.closeQuietly(mEnginePipes[1]);
   7545                     IoUtils.closeQuietly(mTransportPipes[0]);
   7546                     IoUtils.closeQuietly(mTransportPipes[1]);
   7547 
   7548                     // Don't proceed until the engine has torn down the agent etc
   7549                     eThread.waitForResult();
   7550 
   7551                     if (MORE_DEBUG) {
   7552                         Slog.i(TAG, "engine thread finished; proceeding");
   7553                     }
   7554 
   7555                     // Now we're really done with this one too
   7556                     IoUtils.closeQuietly(mEnginePipes[0]);
   7557 
   7558                     // If we hit a transport-level error, we are done with everything;
   7559                     // if we hit an agent error we just go back to running the queue.
   7560                     if (status == BackupTransport.TRANSPORT_OK) {
   7561                         // Clean finish, so just carry on
   7562                         nextState = UnifiedRestoreState.RUNNING_QUEUE;
   7563                     } else {
   7564                         // Something went wrong somewhere.  Whether it was at the transport
   7565                         // level is immaterial; we need to tell the transport to bail
   7566                         try {
   7567                             mTransport.abortFullRestore();
   7568                         } catch (RemoteException e) {
   7569                             // transport itself is dead; make sure we handle this as a
   7570                             // fatal error
   7571                             status = BackupTransport.TRANSPORT_ERROR;
   7572                         }
   7573 
   7574                         // We also need to wipe the current target's data, as it's probably
   7575                         // in an incoherent state.
   7576                         clearApplicationDataSynchronous(mCurrentPackage.packageName);
   7577 
   7578                         // Schedule the next state based on the nature of our failure
   7579                         if (status == BackupTransport.TRANSPORT_ERROR) {
   7580                             nextState = UnifiedRestoreState.FINAL;
   7581                         } else {
   7582                             nextState = UnifiedRestoreState.RUNNING_QUEUE;
   7583                         }
   7584                     }
   7585                     executeNextState(nextState);
   7586                     setRunning(false);
   7587                 }
   7588             }
   7589 
   7590         }
   7591 
   7592         class EngineThread implements Runnable {
   7593             FullRestoreEngine mEngine;
   7594             FileInputStream mEngineStream;
   7595 
   7596             EngineThread(FullRestoreEngine engine, ParcelFileDescriptor engineSocket) {
   7597                 mEngine = engine;
   7598                 engine.setRunning(true);
   7599                 mEngineStream = new FileInputStream(engineSocket.getFileDescriptor());
   7600             }
   7601 
   7602             public boolean isRunning() {
   7603                 return mEngine.isRunning();
   7604             }
   7605 
   7606             public int waitForResult() {
   7607                 return mEngine.waitForResult();
   7608             }
   7609 
   7610             @Override
   7611             public void run() {
   7612                 while (mEngine.isRunning()) {
   7613                     mEngine.restoreOneFile(mEngineStream);
   7614                 }
   7615             }
   7616         }
   7617 
   7618         // state FINAL : tear everything down and we're done.
   7619         private void finalizeRestore() {
   7620             if (MORE_DEBUG) Slog.d(TAG, "finishing restore mObserver=" + mObserver);
   7621 
   7622             try {
   7623                 mTransport.finishRestore();
   7624             } catch (Exception e) {
   7625                 Slog.e(TAG, "Error finishing restore", e);
   7626             }
   7627 
   7628             // Tell the observer we're done
   7629             if (mObserver != null) {
   7630                 try {
   7631                     mObserver.restoreFinished(mStatus);
   7632                 } catch (RemoteException e) {
   7633                     Slog.d(TAG, "Restore observer died at restoreFinished");
   7634                 }
   7635             }
   7636 
   7637             // Clear any ongoing session timeout.
   7638             mBackupHandler.removeMessages(MSG_RESTORE_TIMEOUT);
   7639 
   7640             // If we have a PM token, we must under all circumstances be sure to
   7641             // handshake when we've finished.
   7642             if (mPmToken > 0) {
   7643                 if (MORE_DEBUG) Slog.v(TAG, "finishing PM token " + mPmToken);
   7644                 try {
   7645                     mPackageManagerBinder.finishPackageInstall(mPmToken);
   7646                 } catch (RemoteException e) { /* can't happen */ }
   7647             } else {
   7648                 // We were invoked via an active restore session, not by the Package
   7649                 // Manager, so start up the session timeout again.
   7650                 mBackupHandler.sendEmptyMessageDelayed(MSG_RESTORE_TIMEOUT,
   7651                         TIMEOUT_RESTORE_INTERVAL);
   7652             }
   7653 
   7654             // Kick off any work that may be needed regarding app widget restores
   7655             AppWidgetBackupBridge.restoreFinished(UserHandle.USER_OWNER);
   7656 
   7657             // If this was a full-system restore, record the ancestral
   7658             // dataset information
   7659             if (mIsSystemRestore) {
   7660                 mAncestralPackages = mPmAgent.getRestoredPackages();
   7661                 mAncestralToken = mToken;
   7662                 writeRestoreTokens();
   7663             }
   7664 
   7665             // done; we can finally release the wakelock and be legitimately done.
   7666             Slog.i(TAG, "Restore complete.");
   7667             mWakelock.release();
   7668         }
   7669 
   7670         void keyValueAgentErrorCleanup() {
   7671             // If the agent fails restore, it might have put the app's data
   7672             // into an incoherent state.  For consistency we wipe its data
   7673             // again in this case before continuing with normal teardown
   7674             clearApplicationDataSynchronous(mCurrentPackage.packageName);
   7675             keyValueAgentCleanup();
   7676         }
   7677 
   7678         void keyValueAgentCleanup() {
   7679             mBackupDataName.delete();
   7680             mStageName.delete();
   7681             try { if (mBackupData != null) mBackupData.close(); } catch (IOException e) {}
   7682             try { if (mNewState != null) mNewState.close(); } catch (IOException e) {}
   7683             mBackupData = mNewState = null;
   7684 
   7685             // if everything went okay, remember the recorded state now
   7686             //
   7687             // !!! TODO: the restored data could be migrated on the server
   7688             // side into the current dataset.  In that case the new state file
   7689             // we just created would reflect the data already extant in the
   7690             // backend, so there'd be nothing more to do.  Until that happens,
   7691             // however, we need to make sure that we record the data to the
   7692             // current backend dataset.  (Yes, this means shipping the data over
   7693             // the wire in both directions.  That's bad, but consistency comes
   7694             // first, then efficiency.)  Once we introduce server-side data
   7695             // migration to the newly-restored device's dataset, we will change
   7696             // the following from a discard of the newly-written state to the
   7697             // "correct" operation of renaming into the canonical state blob.
   7698             mNewStateName.delete();                      // TODO: remove; see above comment
   7699             //mNewStateName.renameTo(mSavedStateName);   // TODO: replace with this
   7700 
   7701             // If this wasn't the PM pseudopackage, tear down the agent side
   7702             if (mCurrentPackage.applicationInfo != null) {
   7703                 // unbind and tidy up even on timeout or failure
   7704                 try {
   7705                     mActivityManager.unbindBackupAgent(mCurrentPackage.applicationInfo);
   7706 
   7707                     // The agent was probably running with a stub Application object,
   7708                     // which isn't a valid run mode for the main app logic.  Shut
   7709                     // down the app so that next time it's launched, it gets the
   7710                     // usual full initialization.  Note that this is only done for
   7711                     // full-system restores: when a single app has requested a restore,
   7712                     // it is explicitly not killed following that operation.
   7713                     if (mTargetPackage == null && (mCurrentPackage.applicationInfo.flags
   7714                             & ApplicationInfo.FLAG_KILL_AFTER_RESTORE) != 0) {
   7715                         if (DEBUG) Slog.d(TAG, "Restore complete, killing host process of "
   7716                                 + mCurrentPackage.applicationInfo.processName);
   7717                         mActivityManager.killApplicationProcess(
   7718                                 mCurrentPackage.applicationInfo.processName,
   7719                                 mCurrentPackage.applicationInfo.uid);
   7720                     }
   7721                 } catch (RemoteException e) {
   7722                     // can't happen; we run in the same process as the activity manager
   7723                 }
   7724             }
   7725 
   7726             // The caller is responsible for reestablishing the state machine; our
   7727             // responsibility here is to clear the decks for whatever comes next.
   7728             mBackupHandler.removeMessages(MSG_TIMEOUT, this);
   7729             synchronized (mCurrentOpLock) {
   7730                 mCurrentOperations.clear();
   7731             }
   7732         }
   7733 
   7734         @Override
   7735         public void operationComplete() {
   7736             if (MORE_DEBUG) {
   7737                 Slog.i(TAG, "operationComplete() during restore: target="
   7738                         + mCurrentPackage.packageName
   7739                         + " state=" + mState);
   7740             }
   7741 
   7742             final UnifiedRestoreState nextState;
   7743             switch (mState) {
   7744                 case INITIAL:
   7745                     // We've just (manually) restored the PMBA.  It doesn't need the
   7746                     // additional restore-finished callback so we bypass that and go
   7747                     // directly to running the queue.
   7748                     nextState = UnifiedRestoreState.RUNNING_QUEUE;
   7749                     break;
   7750 
   7751                 case RESTORE_KEYVALUE:
   7752                 case RESTORE_FULL: {
   7753                     // Okay, we've just heard back from the agent that it's done with
   7754                     // the restore itself.  We now have to send the same agent its
   7755                     // doRestoreFinished() callback, so roll into that state.
   7756                     nextState = UnifiedRestoreState.RESTORE_FINISHED;
   7757                     break;
   7758                 }
   7759 
   7760                 case RESTORE_FINISHED: {
   7761                     // Okay, we're done with this package.  Tidy up and go on to the next
   7762                     // app in the queue.
   7763                     int size = (int) mBackupDataName.length();
   7764                     EventLog.writeEvent(EventLogTags.RESTORE_PACKAGE,
   7765                             mCurrentPackage.packageName, size);
   7766 
   7767                     // Just go back to running the restore queue
   7768                     keyValueAgentCleanup();
   7769 
   7770                     // If there was widget state associated with this app, get the OS to
   7771                     // incorporate it into current bookeeping and then pass that along to
   7772                     // the app as part of the restore-time work.
   7773                     if (mWidgetData != null) {
   7774                         restoreWidgetData(mCurrentPackage.packageName, mWidgetData);
   7775                     }
   7776 
   7777                     nextState = UnifiedRestoreState.RUNNING_QUEUE;
   7778                     break;
   7779                 }
   7780 
   7781                 default: {
   7782                     // Some kind of horrible semantic error; we're in an unexpected state.
   7783                     // Back off hard and wind up.
   7784                     Slog.e(TAG, "Unexpected restore callback into state " + mState);
   7785                     keyValueAgentErrorCleanup();
   7786                     nextState = UnifiedRestoreState.FINAL;
   7787                     break;
   7788                 }
   7789             }
   7790 
   7791             executeNextState(nextState);
   7792         }
   7793 
   7794         // A call to agent.doRestore() or agent.doRestoreFinished() has timed out
   7795         @Override
   7796         public void handleTimeout() {
   7797             Slog.e(TAG, "Timeout restoring application " + mCurrentPackage.packageName);
   7798             EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
   7799                     mCurrentPackage.packageName, "restore timeout");
   7800             // Handle like an agent that threw on invocation: wipe it and go on to the next
   7801             keyValueAgentErrorCleanup();
   7802             executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
   7803         }
   7804 
   7805         void executeNextState(UnifiedRestoreState nextState) {
   7806             if (MORE_DEBUG) Slog.i(TAG, " => executing next step on "
   7807                     + this + " nextState=" + nextState);
   7808             mState = nextState;
   7809             Message msg = mBackupHandler.obtainMessage(MSG_BACKUP_RESTORE_STEP, this);
   7810             mBackupHandler.sendMessage(msg);
   7811         }
   7812 
   7813         // restore observer support
   7814         void sendStartRestore(int numPackages) {
   7815             if (mObserver != null) {
   7816                 try {
   7817                     mObserver.restoreStarting(numPackages);
   7818                 } catch (RemoteException e) {
   7819                     Slog.w(TAG, "Restore observer went away: startRestore");
   7820                     mObserver = null;
   7821                 }
   7822             }
   7823         }
   7824 
   7825         void sendOnRestorePackage(String name) {
   7826             if (mObserver != null) {
   7827                 if (mObserver != null) {
   7828                     try {
   7829                         mObserver.onUpdate(mCount, name);
   7830                     } catch (RemoteException e) {
   7831                         Slog.d(TAG, "Restore observer died in onUpdate");
   7832                         mObserver = null;
   7833                     }
   7834                 }
   7835             }
   7836         }
   7837 
   7838         void sendEndRestore() {
   7839             if (mObserver != null) {
   7840                 try {
   7841                     mObserver.restoreFinished(mStatus);
   7842                 } catch (RemoteException e) {
   7843                     Slog.w(TAG, "Restore observer went away: endRestore");
   7844                     mObserver = null;
   7845                 }
   7846             }
   7847         }
   7848     }
   7849 
   7850     class PerformClearTask implements Runnable {
   7851         IBackupTransport mTransport;
   7852         PackageInfo mPackage;
   7853 
   7854         PerformClearTask(IBackupTransport transport, PackageInfo packageInfo) {
   7855             mTransport = transport;
   7856             mPackage = packageInfo;
   7857         }
   7858 
   7859         public void run() {
   7860             try {
   7861                 // Clear the on-device backup state to ensure a full backup next time
   7862                 File stateDir = new File(mBaseStateDir, mTransport.transportDirName());
   7863                 File stateFile = new File(stateDir, mPackage.packageName);
   7864                 stateFile.delete();
   7865 
   7866                 // Tell the transport to remove all the persistent storage for the app
   7867                 // TODO - need to handle failures
   7868                 mTransport.clearBackupData(mPackage);
   7869             } catch (RemoteException e) {
   7870                 // can't happen; the transport is local
   7871             } catch (Exception e) {
   7872                 Slog.e(TAG, "Transport threw attempting to clear data for " + mPackage);
   7873             } finally {
   7874                 try {
   7875                     // TODO - need to handle failures
   7876                     mTransport.finishBackup();
   7877                 } catch (RemoteException e) {
   7878                     // can't happen; the transport is local
   7879                 }
   7880 
   7881                 // Last but not least, release the cpu
   7882                 mWakelock.release();
   7883             }
   7884         }
   7885     }
   7886 
   7887     class PerformInitializeTask implements Runnable {
   7888         HashSet<String> mQueue;
   7889 
   7890         PerformInitializeTask(HashSet<String> transportNames) {
   7891             mQueue = transportNames;
   7892         }
   7893 
   7894         public void run() {
   7895             try {
   7896                 for (String transportName : mQueue) {
   7897                     IBackupTransport transport = getTransport(transportName);
   7898                     if (transport == null) {
   7899                         Slog.e(TAG, "Requested init for " + transportName + " but not found");
   7900                         continue;
   7901                     }
   7902 
   7903                     Slog.i(TAG, "Initializing (wiping) backup transport storage: " + transportName);
   7904                     EventLog.writeEvent(EventLogTags.BACKUP_START, transport.transportDirName());
   7905                     long startRealtime = SystemClock.elapsedRealtime();
   7906                     int status = transport.initializeDevice();
   7907 
   7908                     if (status == BackupTransport.TRANSPORT_OK) {
   7909                         status = transport.finishBackup();
   7910                     }
   7911 
   7912                     // Okay, the wipe really happened.  Clean up our local bookkeeping.
   7913                     if (status == BackupTransport.TRANSPORT_OK) {
   7914                         Slog.i(TAG, "Device init successful");
   7915                         int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
   7916                         EventLog.writeEvent(EventLogTags.BACKUP_INITIALIZE);
   7917                         resetBackupState(new File(mBaseStateDir, transport.transportDirName()));
   7918                         EventLog.writeEvent(EventLogTags.BACKUP_SUCCESS, 0, millis);
   7919                         synchronized (mQueueLock) {
   7920                             recordInitPendingLocked(false, transportName);
   7921                         }
   7922                     } else {
   7923                         // If this didn't work, requeue this one and try again
   7924                         // after a suitable interval
   7925                         Slog.e(TAG, "Transport error in initializeDevice()");
   7926                         EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, "(initialize)");
   7927                         synchronized (mQueueLock) {
   7928                             recordInitPendingLocked(true, transportName);
   7929                         }
   7930                         // do this via another alarm to make sure of the wakelock states
   7931                         long delay = transport.requestBackupTime();
   7932                         if (DEBUG) Slog.w(TAG, "init failed on "
   7933                                 + transportName + " resched in " + delay);
   7934                         mAlarmManager.set(AlarmManager.RTC_WAKEUP,
   7935                                 System.currentTimeMillis() + delay, mRunInitIntent);
   7936                     }
   7937                 }
   7938             } catch (RemoteException e) {
   7939                 // can't happen; the transports are local
   7940             } catch (Exception e) {
   7941                 Slog.e(TAG, "Unexpected error performing init", e);
   7942             } finally {
   7943                 // Done; release the wakelock
   7944                 mWakelock.release();
   7945             }
   7946         }
   7947     }
   7948 
   7949     private void dataChangedImpl(String packageName) {
   7950         HashSet<String> targets = dataChangedTargets(packageName);
   7951         dataChangedImpl(packageName, targets);
   7952     }
   7953 
   7954     private void dataChangedImpl(String packageName, HashSet<String> targets) {
   7955         // Record that we need a backup pass for the caller.  Since multiple callers
   7956         // may share a uid, we need to note all candidates within that uid and schedule
   7957         // a backup pass for each of them.
   7958         EventLog.writeEvent(EventLogTags.BACKUP_DATA_CHANGED, packageName);
   7959 
   7960         if (targets == null) {
   7961             Slog.w(TAG, "dataChanged but no participant pkg='" + packageName + "'"
   7962                    + " uid=" + Binder.getCallingUid());
   7963             return;
   7964         }
   7965 
   7966         synchronized (mQueueLock) {
   7967             // Note that this client has made data changes that need to be backed up
   7968             if (targets.contains(packageName)) {
   7969                 // Add the caller to the set of pending backups.  If there is
   7970                 // one already there, then overwrite it, but no harm done.
   7971                 BackupRequest req = new BackupRequest(packageName);
   7972                 if (mPendingBackups.put(packageName, req) == null) {
   7973                     if (DEBUG) Slog.d(TAG, "Now staging backup of " + packageName);
   7974 
   7975                     // Journal this request in case of crash.  The put()
   7976                     // operation returned null when this package was not already
   7977                     // in the set; we want to avoid touching the disk redundantly.
   7978                     writeToJournalLocked(packageName);
   7979 
   7980                     if (MORE_DEBUG) {
   7981                         int numKeys = mPendingBackups.size();
   7982                         Slog.d(TAG, "Now awaiting backup for " + numKeys + " participants:");
   7983                         for (BackupRequest b : mPendingBackups.values()) {
   7984                             Slog.d(TAG, "    + " + b);
   7985                         }
   7986                     }
   7987                 }
   7988             }
   7989         }
   7990     }
   7991 
   7992     // Note: packageName is currently unused, but may be in the future
   7993     private HashSet<String> dataChangedTargets(String packageName) {
   7994         // If the caller does not hold the BACKUP permission, it can only request a
   7995         // backup of its own data.
   7996         if ((mContext.checkPermission(android.Manifest.permission.BACKUP, Binder.getCallingPid(),
   7997                 Binder.getCallingUid())) == PackageManager.PERMISSION_DENIED) {
   7998             synchronized (mBackupParticipants) {
   7999                 return mBackupParticipants.get(Binder.getCallingUid());
   8000             }
   8001         }
   8002 
   8003         // a caller with full permission can ask to back up any participating app
   8004         // !!! TODO: allow backup of ANY app?
   8005         HashSet<String> targets = new HashSet<String>();
   8006         synchronized (mBackupParticipants) {
   8007             int N = mBackupParticipants.size();
   8008             for (int i = 0; i < N; i++) {
   8009                 HashSet<String> s = mBackupParticipants.valueAt(i);
   8010                 if (s != null) {
   8011                     targets.addAll(s);
   8012                 }
   8013             }
   8014         }
   8015         return targets;
   8016     }
   8017 
   8018     private void writeToJournalLocked(String str) {
   8019         RandomAccessFile out = null;
   8020         try {
   8021             if (mJournal == null) mJournal = File.createTempFile("journal", null, mJournalDir);
   8022             out = new RandomAccessFile(mJournal, "rws");
   8023             out.seek(out.length());
   8024             out.writeUTF(str);
   8025         } catch (IOException e) {
   8026             Slog.e(TAG, "Can't write " + str + " to backup journal", e);
   8027             mJournal = null;
   8028         } finally {
   8029             try { if (out != null) out.close(); } catch (IOException e) {}
   8030         }
   8031     }
   8032 
   8033     // ----- IBackupManager binder interface -----
   8034 
   8035     public void dataChanged(final String packageName) {
   8036         final int callingUserHandle = UserHandle.getCallingUserId();
   8037         if (callingUserHandle != UserHandle.USER_OWNER) {
   8038             // App is running under a non-owner user profile.  For now, we do not back
   8039             // up data from secondary user profiles.
   8040             // TODO: backups for all user profiles.
   8041             if (MORE_DEBUG) {
   8042                 Slog.v(TAG, "dataChanged(" + packageName + ") ignored because it's user "
   8043                         + callingUserHandle);
   8044             }
   8045             return;
   8046         }
   8047 
   8048         final HashSet<String> targets = dataChangedTargets(packageName);
   8049         if (targets == null) {
   8050             Slog.w(TAG, "dataChanged but no participant pkg='" + packageName + "'"
   8051                    + " uid=" + Binder.getCallingUid());
   8052             return;
   8053         }
   8054 
   8055         mBackupHandler.post(new Runnable() {
   8056                 public void run() {
   8057                     dataChangedImpl(packageName, targets);
   8058                 }
   8059             });
   8060     }
   8061 
   8062     // Clear the given package's backup data from the current transport
   8063     public void clearBackupData(String transportName, String packageName) {
   8064         if (DEBUG) Slog.v(TAG, "clearBackupData() of " + packageName + " on " + transportName);
   8065         PackageInfo info;
   8066         try {
   8067             info = mPackageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
   8068         } catch (NameNotFoundException e) {
   8069             Slog.d(TAG, "No such package '" + packageName + "' - not clearing backup data");
   8070             return;
   8071         }
   8072 
   8073         // If the caller does not hold the BACKUP permission, it can only request a
   8074         // wipe of its own backed-up data.
   8075         HashSet<String> apps;
   8076         if ((mContext.checkPermission(android.Manifest.permission.BACKUP, Binder.getCallingPid(),
   8077                 Binder.getCallingUid())) == PackageManager.PERMISSION_DENIED) {
   8078             apps = mBackupParticipants.get(Binder.getCallingUid());
   8079         } else {
   8080             // a caller with full permission can ask to back up any participating app
   8081             // !!! TODO: allow data-clear of ANY app?
   8082             if (DEBUG) Slog.v(TAG, "Privileged caller, allowing clear of other apps");
   8083             apps = new HashSet<String>();
   8084             int N = mBackupParticipants.size();
   8085             for (int i = 0; i < N; i++) {
   8086                 HashSet<String> s = mBackupParticipants.valueAt(i);
   8087                 if (s != null) {
   8088                     apps.addAll(s);
   8089                 }
   8090             }
   8091         }
   8092 
   8093         // Is the given app an available participant?
   8094         if (apps.contains(packageName)) {
   8095             // found it; fire off the clear request
   8096             if (DEBUG) Slog.v(TAG, "Found the app - running clear process");
   8097             mBackupHandler.removeMessages(MSG_RETRY_CLEAR);
   8098             synchronized (mQueueLock) {
   8099                 final IBackupTransport transport = getTransport(transportName);
   8100                 if (transport == null) {
   8101                     // transport is currently unavailable -- make sure to retry
   8102                     Message msg = mBackupHandler.obtainMessage(MSG_RETRY_CLEAR,
   8103                             new ClearRetryParams(transportName, packageName));
   8104                     mBackupHandler.sendMessageDelayed(msg, TRANSPORT_RETRY_INTERVAL);
   8105                     return;
   8106                 }
   8107                 long oldId = Binder.clearCallingIdentity();
   8108                 mWakelock.acquire();
   8109                 Message msg = mBackupHandler.obtainMessage(MSG_RUN_CLEAR,
   8110                         new ClearParams(transport, info));
   8111                 mBackupHandler.sendMessage(msg);
   8112                 Binder.restoreCallingIdentity(oldId);
   8113             }
   8114         }
   8115     }
   8116 
   8117     // Run a backup pass immediately for any applications that have declared
   8118     // that they have pending updates.
   8119     public void backupNow() {
   8120         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "backupNow");
   8121 
   8122         if (DEBUG) Slog.v(TAG, "Scheduling immediate backup pass");
   8123         synchronized (mQueueLock) {
   8124             // Because the alarms we are using can jitter, and we want an *immediate*
   8125             // backup pass to happen, we restart the timer beginning with "next time,"
   8126             // then manually fire the backup trigger intent ourselves.
   8127             startBackupAlarmsLocked(BACKUP_INTERVAL);
   8128             try {
   8129                 mRunBackupIntent.send();
   8130             } catch (PendingIntent.CanceledException e) {
   8131                 // should never happen
   8132                 Slog.e(TAG, "run-backup intent cancelled!");
   8133             }
   8134         }
   8135     }
   8136 
   8137     boolean deviceIsProvisioned() {
   8138         final ContentResolver resolver = mContext.getContentResolver();
   8139         return (Settings.Global.getInt(resolver, Settings.Global.DEVICE_PROVISIONED, 0) != 0);
   8140     }
   8141 
   8142     // Run a *full* backup pass for the given packages, writing the resulting data stream
   8143     // to the supplied file descriptor.  This method is synchronous and does not return
   8144     // to the caller until the backup has been completed.
   8145     //
   8146     // This is the variant used by 'adb backup'; it requires on-screen confirmation
   8147     // by the user because it can be used to offload data over untrusted USB.
   8148     @Override
   8149     public void fullBackup(ParcelFileDescriptor fd, boolean includeApks,
   8150             boolean includeObbs, boolean includeShared, boolean doWidgets,
   8151             boolean doAllApps, boolean includeSystem, boolean compress, String[] pkgList) {
   8152         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "fullBackup");
   8153 
   8154         final int callingUserHandle = UserHandle.getCallingUserId();
   8155         if (callingUserHandle != UserHandle.USER_OWNER) {
   8156             throw new IllegalStateException("Backup supported only for the device owner");
   8157         }
   8158 
   8159         // Validate
   8160         if (!doAllApps) {
   8161             if (!includeShared) {
   8162                 // If we're backing up shared data (sdcard or equivalent), then we can run
   8163                 // without any supplied app names.  Otherwise, we'd be doing no work, so
   8164                 // report the error.
   8165                 if (pkgList == null || pkgList.length == 0) {
   8166                     throw new IllegalArgumentException(
   8167                             "Backup requested but neither shared nor any apps named");
   8168                 }
   8169             }
   8170         }
   8171 
   8172         long oldId = Binder.clearCallingIdentity();
   8173         try {
   8174             // Doesn't make sense to do a full backup prior to setup
   8175             if (!deviceIsProvisioned()) {
   8176                 Slog.i(TAG, "Full backup not supported before setup");
   8177                 return;
   8178             }
   8179 
   8180             if (DEBUG) Slog.v(TAG, "Requesting full backup: apks=" + includeApks
   8181                     + " obb=" + includeObbs + " shared=" + includeShared + " all=" + doAllApps
   8182                     + " system=" + includeSystem + " pkgs=" + pkgList);
   8183             Slog.i(TAG, "Beginning full backup...");
   8184 
   8185             FullBackupParams params = new FullBackupParams(fd, includeApks, includeObbs,
   8186                     includeShared, doWidgets, doAllApps, includeSystem, compress, pkgList);
   8187             final int token = generateToken();
   8188             synchronized (mFullConfirmations) {
   8189                 mFullConfirmations.put(token, params);
   8190             }
   8191 
   8192             // start up the confirmation UI
   8193             if (DEBUG) Slog.d(TAG, "Starting backup confirmation UI, token=" + token);
   8194             if (!startConfirmationUi(token, FullBackup.FULL_BACKUP_INTENT_ACTION)) {
   8195                 Slog.e(TAG, "Unable to launch full backup confirmation");
   8196                 mFullConfirmations.delete(token);
   8197                 return;
   8198             }
   8199 
   8200             // make sure the screen is lit for the user interaction
   8201             mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
   8202 
   8203             // start the confirmation countdown
   8204             startConfirmationTimeout(token, params);
   8205 
   8206             // wait for the backup to be performed
   8207             if (DEBUG) Slog.d(TAG, "Waiting for full backup completion...");
   8208             waitForCompletion(params);
   8209         } finally {
   8210             try {
   8211                 fd.close();
   8212             } catch (IOException e) {
   8213                 // just eat it
   8214             }
   8215             Binder.restoreCallingIdentity(oldId);
   8216             Slog.d(TAG, "Full backup processing complete.");
   8217         }
   8218     }
   8219 
   8220     @Override
   8221     public void fullTransportBackup(String[] pkgNames) {
   8222         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP,
   8223                 "fullTransportBackup");
   8224 
   8225         final int callingUserHandle = UserHandle.getCallingUserId();
   8226         if (callingUserHandle != UserHandle.USER_OWNER) {
   8227             throw new IllegalStateException("Restore supported only for the device owner");
   8228         }
   8229 
   8230         if (DEBUG) {
   8231             Slog.d(TAG, "fullTransportBackup()");
   8232         }
   8233 
   8234         AtomicBoolean latch = new AtomicBoolean(false);
   8235         PerformFullTransportBackupTask task =
   8236                 new PerformFullTransportBackupTask(null, pkgNames, false, null, latch);
   8237         (new Thread(task, "full-transport-master")).start();
   8238         synchronized (latch) {
   8239             try {
   8240                 while (latch.get() == false) {
   8241                     latch.wait();
   8242                 }
   8243             } catch (InterruptedException e) {}
   8244         }
   8245         if (DEBUG) {
   8246             Slog.d(TAG, "Done with full transport backup.");
   8247         }
   8248     }
   8249 
   8250     @Override
   8251     public void fullRestore(ParcelFileDescriptor fd) {
   8252         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "fullRestore");
   8253 
   8254         final int callingUserHandle = UserHandle.getCallingUserId();
   8255         if (callingUserHandle != UserHandle.USER_OWNER) {
   8256             throw new IllegalStateException("Restore supported only for the device owner");
   8257         }
   8258 
   8259         long oldId = Binder.clearCallingIdentity();
   8260 
   8261         try {
   8262             // Check whether the device has been provisioned -- we don't handle
   8263             // full restores prior to completing the setup process.
   8264             if (!deviceIsProvisioned()) {
   8265                 Slog.i(TAG, "Full restore not permitted before setup");
   8266                 return;
   8267             }
   8268 
   8269             Slog.i(TAG, "Beginning full restore...");
   8270 
   8271             FullRestoreParams params = new FullRestoreParams(fd);
   8272             final int token = generateToken();
   8273             synchronized (mFullConfirmations) {
   8274                 mFullConfirmations.put(token, params);
   8275             }
   8276 
   8277             // start up the confirmation UI
   8278             if (DEBUG) Slog.d(TAG, "Starting restore confirmation UI, token=" + token);
   8279             if (!startConfirmationUi(token, FullBackup.FULL_RESTORE_INTENT_ACTION)) {
   8280                 Slog.e(TAG, "Unable to launch full restore confirmation");
   8281                 mFullConfirmations.delete(token);
   8282                 return;
   8283             }
   8284 
   8285             // make sure the screen is lit for the user interaction
   8286             mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
   8287 
   8288             // start the confirmation countdown
   8289             startConfirmationTimeout(token, params);
   8290 
   8291             // wait for the restore to be performed
   8292             if (DEBUG) Slog.d(TAG, "Waiting for full restore completion...");
   8293             waitForCompletion(params);
   8294         } finally {
   8295             try {
   8296                 fd.close();
   8297             } catch (IOException e) {
   8298                 Slog.w(TAG, "Error trying to close fd after full restore: " + e);
   8299             }
   8300             Binder.restoreCallingIdentity(oldId);
   8301             Slog.i(TAG, "Full restore processing complete.");
   8302         }
   8303     }
   8304 
   8305     boolean startConfirmationUi(int token, String action) {
   8306         try {
   8307             Intent confIntent = new Intent(action);
   8308             confIntent.setClassName("com.android.backupconfirm",
   8309                     "com.android.backupconfirm.BackupRestoreConfirmation");
   8310             confIntent.putExtra(FullBackup.CONF_TOKEN_INTENT_EXTRA, token);
   8311             confIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
   8312             mContext.startActivity(confIntent);
   8313         } catch (ActivityNotFoundException e) {
   8314             return false;
   8315         }
   8316         return true;
   8317     }
   8318 
   8319     void startConfirmationTimeout(int token, FullParams params) {
   8320         if (MORE_DEBUG) Slog.d(TAG, "Posting conf timeout msg after "
   8321                 + TIMEOUT_FULL_CONFIRMATION + " millis");
   8322         Message msg = mBackupHandler.obtainMessage(MSG_FULL_CONFIRMATION_TIMEOUT,
   8323                 token, 0, params);
   8324         mBackupHandler.sendMessageDelayed(msg, TIMEOUT_FULL_CONFIRMATION);
   8325     }
   8326 
   8327     void waitForCompletion(FullParams params) {
   8328         synchronized (params.latch) {
   8329             while (params.latch.get() == false) {
   8330                 try {
   8331                     params.latch.wait();
   8332                 } catch (InterruptedException e) { /* never interrupted */ }
   8333             }
   8334         }
   8335     }
   8336 
   8337     void signalFullBackupRestoreCompletion(FullParams params) {
   8338         synchronized (params.latch) {
   8339             params.latch.set(true);
   8340             params.latch.notifyAll();
   8341         }
   8342     }
   8343 
   8344     // Confirm that the previously-requested full backup/restore operation can proceed.  This
   8345     // is used to require a user-facing disclosure about the operation.
   8346     @Override
   8347     public void acknowledgeFullBackupOrRestore(int token, boolean allow,
   8348             String curPassword, String encPpassword, IFullBackupRestoreObserver observer) {
   8349         if (DEBUG) Slog.d(TAG, "acknowledgeFullBackupOrRestore : token=" + token
   8350                 + " allow=" + allow);
   8351 
   8352         // TODO: possibly require not just this signature-only permission, but even
   8353         // require that the specific designated confirmation-UI app uid is the caller?
   8354         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "acknowledgeFullBackupOrRestore");
   8355 
   8356         long oldId = Binder.clearCallingIdentity();
   8357         try {
   8358 
   8359             FullParams params;
   8360             synchronized (mFullConfirmations) {
   8361                 params = mFullConfirmations.get(token);
   8362                 if (params != null) {
   8363                     mBackupHandler.removeMessages(MSG_FULL_CONFIRMATION_TIMEOUT, params);
   8364                     mFullConfirmations.delete(token);
   8365 
   8366                     if (allow) {
   8367                         final int verb = params instanceof FullBackupParams
   8368                                 ? MSG_RUN_ADB_BACKUP
   8369                                 : MSG_RUN_ADB_RESTORE;
   8370 
   8371                         params.observer = observer;
   8372                         params.curPassword = curPassword;
   8373 
   8374                         params.encryptPassword = encPpassword;
   8375 
   8376                         if (DEBUG) Slog.d(TAG, "Sending conf message with verb " + verb);
   8377                         mWakelock.acquire();
   8378                         Message msg = mBackupHandler.obtainMessage(verb, params);
   8379                         mBackupHandler.sendMessage(msg);
   8380                     } else {
   8381                         Slog.w(TAG, "User rejected full backup/restore operation");
   8382                         // indicate completion without having actually transferred any data
   8383                         signalFullBackupRestoreCompletion(params);
   8384                     }
   8385                 } else {
   8386                     Slog.w(TAG, "Attempted to ack full backup/restore with invalid token");
   8387                 }
   8388             }
   8389         } finally {
   8390             Binder.restoreCallingIdentity(oldId);
   8391         }
   8392     }
   8393 
   8394     // Enable/disable the backup service
   8395     @Override
   8396     public void setBackupEnabled(boolean enable) {
   8397         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   8398                 "setBackupEnabled");
   8399 
   8400         Slog.i(TAG, "Backup enabled => " + enable);
   8401 
   8402         long oldId = Binder.clearCallingIdentity();
   8403         try {
   8404             boolean wasEnabled = mEnabled;
   8405             synchronized (this) {
   8406                 Settings.Secure.putInt(mContext.getContentResolver(),
   8407                         Settings.Secure.BACKUP_ENABLED, enable ? 1 : 0);
   8408                 mEnabled = enable;
   8409             }
   8410 
   8411             synchronized (mQueueLock) {
   8412                 if (enable && !wasEnabled && mProvisioned) {
   8413                     // if we've just been enabled, start scheduling backup passes
   8414                     startBackupAlarmsLocked(BACKUP_INTERVAL);
   8415                     scheduleNextFullBackupJob();
   8416                 } else if (!enable) {
   8417                     // No longer enabled, so stop running backups
   8418                     if (DEBUG) Slog.i(TAG, "Opting out of backup");
   8419 
   8420                     mAlarmManager.cancel(mRunBackupIntent);
   8421 
   8422                     // This also constitutes an opt-out, so we wipe any data for
   8423                     // this device from the backend.  We start that process with
   8424                     // an alarm in order to guarantee wakelock states.
   8425                     if (wasEnabled && mProvisioned) {
   8426                         // NOTE: we currently flush every registered transport, not just
   8427                         // the currently-active one.
   8428                         HashSet<String> allTransports;
   8429                         synchronized (mTransports) {
   8430                             allTransports = new HashSet<String>(mTransports.keySet());
   8431                         }
   8432                         // build the set of transports for which we are posting an init
   8433                         for (String transport : allTransports) {
   8434                             recordInitPendingLocked(true, transport);
   8435                         }
   8436                         mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
   8437                                 mRunInitIntent);
   8438                     }
   8439                 }
   8440             }
   8441         } finally {
   8442             Binder.restoreCallingIdentity(oldId);
   8443         }
   8444     }
   8445 
   8446     // Enable/disable automatic restore of app data at install time
   8447     public void setAutoRestore(boolean doAutoRestore) {
   8448         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   8449                 "setAutoRestore");
   8450 
   8451         Slog.i(TAG, "Auto restore => " + doAutoRestore);
   8452 
   8453         final long oldId = Binder.clearCallingIdentity();
   8454         try {
   8455             synchronized (this) {
   8456                 Settings.Secure.putInt(mContext.getContentResolver(),
   8457                         Settings.Secure.BACKUP_AUTO_RESTORE, doAutoRestore ? 1 : 0);
   8458                 mAutoRestore = doAutoRestore;
   8459             }
   8460         } finally {
   8461             Binder.restoreCallingIdentity(oldId);
   8462         }
   8463     }
   8464 
   8465     // Mark the backup service as having been provisioned
   8466     public void setBackupProvisioned(boolean available) {
   8467         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   8468                 "setBackupProvisioned");
   8469         /*
   8470          * This is now a no-op; provisioning is simply the device's own setup state.
   8471          */
   8472     }
   8473 
   8474     private void startBackupAlarmsLocked(long delayBeforeFirstBackup) {
   8475         // We used to use setInexactRepeating(), but that may be linked to
   8476         // backups running at :00 more often than not, creating load spikes.
   8477         // Schedule at an exact time for now, and also add a bit of "fuzz".
   8478 
   8479         Random random = new Random();
   8480         long when = System.currentTimeMillis() + delayBeforeFirstBackup +
   8481                 random.nextInt(FUZZ_MILLIS);
   8482         mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, when,
   8483                 BACKUP_INTERVAL + random.nextInt(FUZZ_MILLIS), mRunBackupIntent);
   8484         mNextBackupPass = when;
   8485     }
   8486 
   8487     // Report whether the backup mechanism is currently enabled
   8488     public boolean isBackupEnabled() {
   8489         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "isBackupEnabled");
   8490         return mEnabled;    // no need to synchronize just to read it
   8491     }
   8492 
   8493     // Report the name of the currently active transport
   8494     public String getCurrentTransport() {
   8495         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   8496                 "getCurrentTransport");
   8497         if (MORE_DEBUG) Slog.v(TAG, "... getCurrentTransport() returning " + mCurrentTransport);
   8498         return mCurrentTransport;
   8499     }
   8500 
   8501     // Report all known, available backup transports
   8502     public String[] listAllTransports() {
   8503         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "listAllTransports");
   8504 
   8505         String[] list = null;
   8506         ArrayList<String> known = new ArrayList<String>();
   8507         for (Map.Entry<String, IBackupTransport> entry : mTransports.entrySet()) {
   8508             if (entry.getValue() != null) {
   8509                 known.add(entry.getKey());
   8510             }
   8511         }
   8512 
   8513         if (known.size() > 0) {
   8514             list = new String[known.size()];
   8515             known.toArray(list);
   8516         }
   8517         return list;
   8518     }
   8519 
   8520     // Select which transport to use for the next backup operation.
   8521     public String selectBackupTransport(String transport) {
   8522         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   8523                 "selectBackupTransport");
   8524 
   8525         synchronized (mTransports) {
   8526             final long oldId = Binder.clearCallingIdentity();
   8527             try {
   8528                 String prevTransport = mCurrentTransport;
   8529                 mCurrentTransport = transport;
   8530                 Settings.Secure.putString(mContext.getContentResolver(),
   8531                         Settings.Secure.BACKUP_TRANSPORT, transport);
   8532                 Slog.v(TAG, "selectBackupTransport() set " + mCurrentTransport
   8533                         + " returning " + prevTransport);
   8534                 return prevTransport;
   8535             } finally {
   8536                 Binder.restoreCallingIdentity(oldId);
   8537             }
   8538         }
   8539     }
   8540 
   8541     // Supply the configuration Intent for the given transport.  If the name is not one
   8542     // of the available transports, or if the transport does not supply any configuration
   8543     // UI, the method returns null.
   8544     public Intent getConfigurationIntent(String transportName) {
   8545         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   8546                 "getConfigurationIntent");
   8547 
   8548         synchronized (mTransports) {
   8549             final IBackupTransport transport = mTransports.get(transportName);
   8550             if (transport != null) {
   8551                 try {
   8552                     final Intent intent = transport.configurationIntent();
   8553                     if (MORE_DEBUG) Slog.d(TAG, "getConfigurationIntent() returning config intent "
   8554                             + intent);
   8555                     return intent;
   8556                 } catch (RemoteException e) {
   8557                     /* fall through to return null */
   8558                 }
   8559             }
   8560         }
   8561 
   8562         return null;
   8563     }
   8564 
   8565     // Supply the configuration summary string for the given transport.  If the name is
   8566     // not one of the available transports, or if the transport does not supply any
   8567     // summary / destination string, the method can return null.
   8568     //
   8569     // This string is used VERBATIM as the summary text of the relevant Settings item!
   8570     public String getDestinationString(String transportName) {
   8571         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   8572                 "getDestinationString");
   8573 
   8574         synchronized (mTransports) {
   8575             final IBackupTransport transport = mTransports.get(transportName);
   8576             if (transport != null) {
   8577                 try {
   8578                     final String text = transport.currentDestinationString();
   8579                     if (MORE_DEBUG) Slog.d(TAG, "getDestinationString() returning " + text);
   8580                     return text;
   8581                 } catch (RemoteException e) {
   8582                     /* fall through to return null */
   8583                 }
   8584             }
   8585         }
   8586 
   8587         return null;
   8588     }
   8589 
   8590     // Supply the manage-data intent for the given transport.
   8591     public Intent getDataManagementIntent(String transportName) {
   8592         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   8593                 "getDataManagementIntent");
   8594 
   8595         synchronized (mTransports) {
   8596             final IBackupTransport transport = mTransports.get(transportName);
   8597             if (transport != null) {
   8598                 try {
   8599                     final Intent intent = transport.dataManagementIntent();
   8600                     if (MORE_DEBUG) Slog.d(TAG, "getDataManagementIntent() returning intent "
   8601                             + intent);
   8602                     return intent;
   8603                 } catch (RemoteException e) {
   8604                     /* fall through to return null */
   8605                 }
   8606             }
   8607         }
   8608 
   8609         return null;
   8610     }
   8611 
   8612     // Supply the menu label for affordances that fire the manage-data intent
   8613     // for the given transport.
   8614     public String getDataManagementLabel(String transportName) {
   8615         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   8616                 "getDataManagementLabel");
   8617 
   8618         synchronized (mTransports) {
   8619             final IBackupTransport transport = mTransports.get(transportName);
   8620             if (transport != null) {
   8621                 try {
   8622                     final String text = transport.dataManagementLabel();
   8623                     if (MORE_DEBUG) Slog.d(TAG, "getDataManagementLabel() returning " + text);
   8624                     return text;
   8625                 } catch (RemoteException e) {
   8626                     /* fall through to return null */
   8627                 }
   8628             }
   8629         }
   8630 
   8631         return null;
   8632     }
   8633 
   8634     // Callback: a requested backup agent has been instantiated.  This should only
   8635     // be called from the Activity Manager.
   8636     public void agentConnected(String packageName, IBinder agentBinder) {
   8637         synchronized(mAgentConnectLock) {
   8638             if (Binder.getCallingUid() == Process.SYSTEM_UID) {
   8639                 Slog.d(TAG, "agentConnected pkg=" + packageName + " agent=" + agentBinder);
   8640                 IBackupAgent agent = IBackupAgent.Stub.asInterface(agentBinder);
   8641                 mConnectedAgent = agent;
   8642                 mConnecting = false;
   8643             } else {
   8644                 Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
   8645                         + " claiming agent connected");
   8646             }
   8647             mAgentConnectLock.notifyAll();
   8648         }
   8649     }
   8650 
   8651     // Callback: a backup agent has failed to come up, or has unexpectedly quit.
   8652     // If the agent failed to come up in the first place, the agentBinder argument
   8653     // will be null.  This should only be called from the Activity Manager.
   8654     public void agentDisconnected(String packageName) {
   8655         // TODO: handle backup being interrupted
   8656         synchronized(mAgentConnectLock) {
   8657             if (Binder.getCallingUid() == Process.SYSTEM_UID) {
   8658                 mConnectedAgent = null;
   8659                 mConnecting = false;
   8660             } else {
   8661                 Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
   8662                         + " claiming agent disconnected");
   8663             }
   8664             mAgentConnectLock.notifyAll();
   8665         }
   8666     }
   8667 
   8668     // An application being installed will need a restore pass, then the Package Manager
   8669     // will need to be told when the restore is finished.
   8670     public void restoreAtInstall(String packageName, int token) {
   8671         if (Binder.getCallingUid() != Process.SYSTEM_UID) {
   8672             Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
   8673                     + " attemping install-time restore");
   8674             return;
   8675         }
   8676 
   8677         boolean skip = false;
   8678 
   8679         long restoreSet = getAvailableRestoreToken(packageName);
   8680         if (DEBUG) Slog.v(TAG, "restoreAtInstall pkg=" + packageName
   8681                 + " token=" + Integer.toHexString(token)
   8682                 + " restoreSet=" + Long.toHexString(restoreSet));
   8683         if (restoreSet == 0) {
   8684             if (MORE_DEBUG) Slog.i(TAG, "No restore set");
   8685             skip = true;
   8686         }
   8687 
   8688         // Do we have a transport to fetch data for us?
   8689         IBackupTransport transport = getTransport(mCurrentTransport);
   8690         if (transport == null) {
   8691             if (DEBUG) Slog.w(TAG, "No transport");
   8692             skip = true;
   8693         }
   8694 
   8695         if (!mAutoRestore) {
   8696             if (DEBUG) {
   8697                 Slog.w(TAG, "Non-restorable state: auto=" + mAutoRestore);
   8698             }
   8699             skip = true;
   8700         }
   8701 
   8702         if (!skip) {
   8703             try {
   8704                 // okay, we're going to attempt a restore of this package from this restore set.
   8705                 // The eventual message back into the Package Manager to run the post-install
   8706                 // steps for 'token' will be issued from the restore handling code.
   8707 
   8708                 // This can throw and so *must* happen before the wakelock is acquired
   8709                 String dirName = transport.transportDirName();
   8710 
   8711                 // We can use a synthetic PackageInfo here because:
   8712                 //   1. We know it's valid, since the Package Manager supplied the name
   8713                 //   2. Only the packageName field will be used by the restore code
   8714                 PackageInfo pkg = new PackageInfo();
   8715                 pkg.packageName = packageName;
   8716 
   8717                 mWakelock.acquire();
   8718                 if (MORE_DEBUG) {
   8719                     Slog.d(TAG, "Restore at install of " + packageName);
   8720                 }
   8721                 Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
   8722                 msg.obj = new RestoreParams(transport, dirName, null,
   8723                         restoreSet, pkg, token);
   8724                 mBackupHandler.sendMessage(msg);
   8725             } catch (RemoteException e) {
   8726                 // Binding to the transport broke; back off and proceed with the installation.
   8727                 Slog.e(TAG, "Unable to contact transport");
   8728                 skip = true;
   8729             }
   8730         }
   8731 
   8732         if (skip) {
   8733             // Auto-restore disabled or no way to attempt a restore; just tell the Package
   8734             // Manager to proceed with the post-install handling for this package.
   8735             if (DEBUG) Slog.v(TAG, "Finishing install immediately");
   8736             try {
   8737                 mPackageManagerBinder.finishPackageInstall(token);
   8738             } catch (RemoteException e) { /* can't happen */ }
   8739         }
   8740     }
   8741 
   8742     // Hand off a restore session
   8743     public IRestoreSession beginRestoreSession(String packageName, String transport) {
   8744         if (DEBUG) Slog.v(TAG, "beginRestoreSession: pkg=" + packageName
   8745                 + " transport=" + transport);
   8746 
   8747         boolean needPermission = true;
   8748         if (transport == null) {
   8749             transport = mCurrentTransport;
   8750 
   8751             if (packageName != null) {
   8752                 PackageInfo app = null;
   8753                 try {
   8754                     app = mPackageManager.getPackageInfo(packageName, 0);
   8755                 } catch (NameNotFoundException nnf) {
   8756                     Slog.w(TAG, "Asked to restore nonexistent pkg " + packageName);
   8757                     throw new IllegalArgumentException("Package " + packageName + " not found");
   8758                 }
   8759 
   8760                 if (app.applicationInfo.uid == Binder.getCallingUid()) {
   8761                     // So: using the current active transport, and the caller has asked
   8762                     // that its own package will be restored.  In this narrow use case
   8763                     // we do not require the caller to hold the permission.
   8764                     needPermission = false;
   8765                 }
   8766             }
   8767         }
   8768 
   8769         if (needPermission) {
   8770             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   8771                     "beginRestoreSession");
   8772         } else {
   8773             if (DEBUG) Slog.d(TAG, "restoring self on current transport; no permission needed");
   8774         }
   8775 
   8776         synchronized(this) {
   8777             if (mActiveRestoreSession != null) {
   8778                 Slog.d(TAG, "Restore session requested but one already active");
   8779                 return null;
   8780             }
   8781             mActiveRestoreSession = new ActiveRestoreSession(packageName, transport);
   8782             mBackupHandler.sendEmptyMessageDelayed(MSG_RESTORE_TIMEOUT, TIMEOUT_RESTORE_INTERVAL);
   8783         }
   8784         return mActiveRestoreSession;
   8785     }
   8786 
   8787     void clearRestoreSession(ActiveRestoreSession currentSession) {
   8788         synchronized(this) {
   8789             if (currentSession != mActiveRestoreSession) {
   8790                 Slog.e(TAG, "ending non-current restore session");
   8791             } else {
   8792                 if (DEBUG) Slog.v(TAG, "Clearing restore session and halting timeout");
   8793                 mActiveRestoreSession = null;
   8794                 mBackupHandler.removeMessages(MSG_RESTORE_TIMEOUT);
   8795             }
   8796         }
   8797     }
   8798 
   8799     // Note that a currently-active backup agent has notified us that it has
   8800     // completed the given outstanding asynchronous backup/restore operation.
   8801     @Override
   8802     public void opComplete(int token) {
   8803         if (MORE_DEBUG) Slog.v(TAG, "opComplete: " + Integer.toHexString(token));
   8804         Operation op = null;
   8805         synchronized (mCurrentOpLock) {
   8806             op = mCurrentOperations.get(token);
   8807             if (op != null) {
   8808                 op.state = OP_ACKNOWLEDGED;
   8809             }
   8810             mCurrentOpLock.notifyAll();
   8811         }
   8812 
   8813         // The completion callback, if any, is invoked on the handler
   8814         if (op != null && op.callback != null) {
   8815             Message msg = mBackupHandler.obtainMessage(MSG_OP_COMPLETE, op.callback);
   8816             mBackupHandler.sendMessage(msg);
   8817         }
   8818     }
   8819 
   8820     // ----- Restore session -----
   8821 
   8822     class ActiveRestoreSession extends IRestoreSession.Stub {
   8823         private static final String TAG = "RestoreSession";
   8824 
   8825         private String mPackageName;
   8826         private IBackupTransport mRestoreTransport = null;
   8827         RestoreSet[] mRestoreSets = null;
   8828         boolean mEnded = false;
   8829         boolean mTimedOut = false;
   8830 
   8831         ActiveRestoreSession(String packageName, String transport) {
   8832             mPackageName = packageName;
   8833             mRestoreTransport = getTransport(transport);
   8834         }
   8835 
   8836         public void markTimedOut() {
   8837             mTimedOut = true;
   8838         }
   8839 
   8840         // --- Binder interface ---
   8841         public synchronized int getAvailableRestoreSets(IRestoreObserver observer) {
   8842             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   8843                     "getAvailableRestoreSets");
   8844             if (observer == null) {
   8845                 throw new IllegalArgumentException("Observer must not be null");
   8846             }
   8847 
   8848             if (mEnded) {
   8849                 throw new IllegalStateException("Restore session already ended");
   8850             }
   8851 
   8852             if (mTimedOut) {
   8853                 Slog.i(TAG, "Session already timed out");
   8854                 return -1;
   8855             }
   8856 
   8857             long oldId = Binder.clearCallingIdentity();
   8858             try {
   8859                 if (mRestoreTransport == null) {
   8860                     Slog.w(TAG, "Null transport getting restore sets");
   8861                     return -1;
   8862                 }
   8863 
   8864                 // We know we're doing legit work now, so halt the timeout
   8865                 // until we're done.  It gets started again when the result
   8866                 // comes in.
   8867                 mBackupHandler.removeMessages(MSG_RESTORE_TIMEOUT);
   8868 
   8869                 // spin off the transport request to our service thread
   8870                 mWakelock.acquire();
   8871                 Message msg = mBackupHandler.obtainMessage(MSG_RUN_GET_RESTORE_SETS,
   8872                         new RestoreGetSetsParams(mRestoreTransport, this, observer));
   8873                 mBackupHandler.sendMessage(msg);
   8874                 return 0;
   8875             } catch (Exception e) {
   8876                 Slog.e(TAG, "Error in getAvailableRestoreSets", e);
   8877                 return -1;
   8878             } finally {
   8879                 Binder.restoreCallingIdentity(oldId);
   8880             }
   8881         }
   8882 
   8883         public synchronized int restoreAll(long token, IRestoreObserver observer) {
   8884             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   8885                     "performRestore");
   8886 
   8887             if (DEBUG) Slog.d(TAG, "restoreAll token=" + Long.toHexString(token)
   8888                     + " observer=" + observer);
   8889 
   8890             if (mEnded) {
   8891                 throw new IllegalStateException("Restore session already ended");
   8892             }
   8893 
   8894             if (mTimedOut) {
   8895                 Slog.i(TAG, "Session already timed out");
   8896                 return -1;
   8897             }
   8898 
   8899             if (mRestoreTransport == null || mRestoreSets == null) {
   8900                 Slog.e(TAG, "Ignoring restoreAll() with no restore set");
   8901                 return -1;
   8902             }
   8903 
   8904             if (mPackageName != null) {
   8905                 Slog.e(TAG, "Ignoring restoreAll() on single-package session");
   8906                 return -1;
   8907             }
   8908 
   8909             String dirName;
   8910             try {
   8911                 dirName = mRestoreTransport.transportDirName();
   8912             } catch (RemoteException e) {
   8913                 // Transport went AWOL; fail.
   8914                 Slog.e(TAG, "Unable to contact transport for restore");
   8915                 return -1;
   8916             }
   8917 
   8918             synchronized (mQueueLock) {
   8919                 for (int i = 0; i < mRestoreSets.length; i++) {
   8920                     if (token == mRestoreSets[i].token) {
   8921                         // Real work, so stop the session timeout until we finalize the restore
   8922                         mBackupHandler.removeMessages(MSG_RESTORE_TIMEOUT);
   8923 
   8924                         long oldId = Binder.clearCallingIdentity();
   8925                         mWakelock.acquire();
   8926                         if (MORE_DEBUG) {
   8927                             Slog.d(TAG, "restoreAll() kicking off");
   8928                         }
   8929                         Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
   8930                         msg.obj = new RestoreParams(mRestoreTransport, dirName,
   8931                                 observer, token);
   8932                         mBackupHandler.sendMessage(msg);
   8933                         Binder.restoreCallingIdentity(oldId);
   8934                         return 0;
   8935                     }
   8936                 }
   8937             }
   8938 
   8939             Slog.w(TAG, "Restore token " + Long.toHexString(token) + " not found");
   8940             return -1;
   8941         }
   8942 
   8943         // Restores of more than a single package are treated as 'system' restores
   8944         public synchronized int restoreSome(long token, IRestoreObserver observer,
   8945                 String[] packages) {
   8946             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   8947                     "performRestore");
   8948 
   8949             if (DEBUG) {
   8950                 StringBuilder b = new StringBuilder(128);
   8951                 b.append("restoreSome token=");
   8952                 b.append(Long.toHexString(token));
   8953                 b.append(" observer=");
   8954                 b.append(observer.toString());
   8955                 b.append(" packages=");
   8956                 if (packages == null) {
   8957                     b.append("null");
   8958                 } else {
   8959                     b.append('{');
   8960                     boolean first = true;
   8961                     for (String s : packages) {
   8962                         if (!first) {
   8963                             b.append(", ");
   8964                         } else first = false;
   8965                         b.append(s);
   8966                     }
   8967                     b.append('}');
   8968                 }
   8969                 Slog.d(TAG, b.toString());
   8970             }
   8971 
   8972             if (mEnded) {
   8973                 throw new IllegalStateException("Restore session already ended");
   8974             }
   8975 
   8976             if (mTimedOut) {
   8977                 Slog.i(TAG, "Session already timed out");
   8978                 return -1;
   8979             }
   8980 
   8981             if (mRestoreTransport == null || mRestoreSets == null) {
   8982                 Slog.e(TAG, "Ignoring restoreAll() with no restore set");
   8983                 return -1;
   8984             }
   8985 
   8986             if (mPackageName != null) {
   8987                 Slog.e(TAG, "Ignoring restoreAll() on single-package session");
   8988                 return -1;
   8989             }
   8990 
   8991             String dirName;
   8992             try {
   8993                 dirName = mRestoreTransport.transportDirName();
   8994             } catch (RemoteException e) {
   8995                 // Transport went AWOL; fail.
   8996                 Slog.e(TAG, "Unable to contact transport for restore");
   8997                 return -1;
   8998             }
   8999 
   9000             synchronized (mQueueLock) {
   9001                 for (int i = 0; i < mRestoreSets.length; i++) {
   9002                     if (token == mRestoreSets[i].token) {
   9003                         // Stop the session timeout until we finalize the restore
   9004                         mBackupHandler.removeMessages(MSG_RESTORE_TIMEOUT);
   9005 
   9006                         long oldId = Binder.clearCallingIdentity();
   9007                         mWakelock.acquire();
   9008                         if (MORE_DEBUG) {
   9009                             Slog.d(TAG, "restoreSome() of " + packages.length + " packages");
   9010                         }
   9011                         Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
   9012                         msg.obj = new RestoreParams(mRestoreTransport, dirName, observer, token,
   9013                                 packages, packages.length > 1);
   9014                         mBackupHandler.sendMessage(msg);
   9015                         Binder.restoreCallingIdentity(oldId);
   9016                         return 0;
   9017                     }
   9018                 }
   9019             }
   9020 
   9021             Slog.w(TAG, "Restore token " + Long.toHexString(token) + " not found");
   9022             return -1;
   9023         }
   9024 
   9025         public synchronized int restorePackage(String packageName, IRestoreObserver observer) {
   9026             if (DEBUG) Slog.v(TAG, "restorePackage pkg=" + packageName + " obs=" + observer);
   9027 
   9028             if (mEnded) {
   9029                 throw new IllegalStateException("Restore session already ended");
   9030             }
   9031 
   9032             if (mTimedOut) {
   9033                 Slog.i(TAG, "Session already timed out");
   9034                 return -1;
   9035             }
   9036 
   9037             if (mPackageName != null) {
   9038                 if (! mPackageName.equals(packageName)) {
   9039                     Slog.e(TAG, "Ignoring attempt to restore pkg=" + packageName
   9040                             + " on session for package " + mPackageName);
   9041                     return -1;
   9042                 }
   9043             }
   9044 
   9045             PackageInfo app = null;
   9046             try {
   9047                 app = mPackageManager.getPackageInfo(packageName, 0);
   9048             } catch (NameNotFoundException nnf) {
   9049                 Slog.w(TAG, "Asked to restore nonexistent pkg " + packageName);
   9050                 return -1;
   9051             }
   9052 
   9053             // If the caller is not privileged and is not coming from the target
   9054             // app's uid, throw a permission exception back to the caller.
   9055             int perm = mContext.checkPermission(android.Manifest.permission.BACKUP,
   9056                     Binder.getCallingPid(), Binder.getCallingUid());
   9057             if ((perm == PackageManager.PERMISSION_DENIED) &&
   9058                     (app.applicationInfo.uid != Binder.getCallingUid())) {
   9059                 Slog.w(TAG, "restorePackage: bad packageName=" + packageName
   9060                         + " or calling uid=" + Binder.getCallingUid());
   9061                 throw new SecurityException("No permission to restore other packages");
   9062             }
   9063 
   9064             // So far so good; we're allowed to try to restore this package.  Now
   9065             // check whether there is data for it in the current dataset, falling back
   9066             // to the ancestral dataset if not.
   9067             long token = getAvailableRestoreToken(packageName);
   9068 
   9069             // If we didn't come up with a place to look -- no ancestral dataset and
   9070             // the app has never been backed up from this device -- there's nothing
   9071             // to do but return failure.
   9072             if (token == 0) {
   9073                 if (DEBUG) Slog.w(TAG, "No data available for this package; not restoring");
   9074                 return -1;
   9075             }
   9076 
   9077             String dirName;
   9078             try {
   9079                 dirName = mRestoreTransport.transportDirName();
   9080             } catch (RemoteException e) {
   9081                 // Transport went AWOL; fail.
   9082                 Slog.e(TAG, "Unable to contact transport for restore");
   9083                 return -1;
   9084             }
   9085 
   9086             // Stop the session timeout until we finalize the restore
   9087             mBackupHandler.removeMessages(MSG_RESTORE_TIMEOUT);
   9088 
   9089             // Ready to go:  enqueue the restore request and claim success
   9090             long oldId = Binder.clearCallingIdentity();
   9091             mWakelock.acquire();
   9092             if (MORE_DEBUG) {
   9093                 Slog.d(TAG, "restorePackage() : " + packageName);
   9094             }
   9095             Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
   9096             msg.obj = new RestoreParams(mRestoreTransport, dirName,
   9097                     observer, token, app, 0);
   9098             mBackupHandler.sendMessage(msg);
   9099             Binder.restoreCallingIdentity(oldId);
   9100             return 0;
   9101         }
   9102 
   9103         // Posted to the handler to tear down a restore session in a cleanly synchronized way
   9104         class EndRestoreRunnable implements Runnable {
   9105             BackupManagerService mBackupManager;
   9106             ActiveRestoreSession mSession;
   9107 
   9108             EndRestoreRunnable(BackupManagerService manager, ActiveRestoreSession session) {
   9109                 mBackupManager = manager;
   9110                 mSession = session;
   9111             }
   9112 
   9113             public void run() {
   9114                 // clean up the session's bookkeeping
   9115                 synchronized (mSession) {
   9116                     try {
   9117                         if (mSession.mRestoreTransport != null) {
   9118                             mSession.mRestoreTransport.finishRestore();
   9119                         }
   9120                     } catch (Exception e) {
   9121                         Slog.e(TAG, "Error in finishRestore", e);
   9122                     } finally {
   9123                         mSession.mRestoreTransport = null;
   9124                         mSession.mEnded = true;
   9125                     }
   9126                 }
   9127 
   9128                 // clean up the BackupManagerImpl side of the bookkeeping
   9129                 // and cancel any pending timeout message
   9130                 mBackupManager.clearRestoreSession(mSession);
   9131             }
   9132         }
   9133 
   9134         public synchronized void endRestoreSession() {
   9135             if (DEBUG) Slog.d(TAG, "endRestoreSession");
   9136 
   9137             if (mTimedOut) {
   9138                 Slog.i(TAG, "Session already timed out");
   9139                 return;
   9140             }
   9141 
   9142             if (mEnded) {
   9143                 throw new IllegalStateException("Restore session already ended");
   9144             }
   9145 
   9146             mBackupHandler.post(new EndRestoreRunnable(BackupManagerService.this, this));
   9147         }
   9148     }
   9149 
   9150     @Override
   9151     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   9152         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
   9153 
   9154         long identityToken = Binder.clearCallingIdentity();
   9155         try {
   9156             if (args != null) {
   9157                 for (String arg : args) {
   9158                     if ("-h".equals(arg)) {
   9159                         pw.println("'dumpsys backup' optional arguments:");
   9160                         pw.println("  -h       : this help text");
   9161                         pw.println("  a[gents] : dump information about defined backup agents");
   9162                         return;
   9163                     } else if ("agents".startsWith(arg)) {
   9164                         dumpAgents(pw);
   9165                         return;
   9166                     }
   9167                 }
   9168             }
   9169             dumpInternal(pw);
   9170         } finally {
   9171             Binder.restoreCallingIdentity(identityToken);
   9172         }
   9173     }
   9174 
   9175     private void dumpAgents(PrintWriter pw) {
   9176         List<PackageInfo> agentPackages = allAgentPackages();
   9177         pw.println("Defined backup agents:");
   9178         for (PackageInfo pkg : agentPackages) {
   9179             pw.print("  ");
   9180             pw.print(pkg.packageName); pw.println(':');
   9181             pw.print("      "); pw.println(pkg.applicationInfo.backupAgentName);
   9182         }
   9183     }
   9184 
   9185     private void dumpInternal(PrintWriter pw) {
   9186         synchronized (mQueueLock) {
   9187             pw.println("Backup Manager is " + (mEnabled ? "enabled" : "disabled")
   9188                     + " / " + (!mProvisioned ? "not " : "") + "provisioned / "
   9189                     + (this.mPendingInits.size() == 0 ? "not " : "") + "pending init");
   9190             pw.println("Auto-restore is " + (mAutoRestore ? "enabled" : "disabled"));
   9191             if (mBackupRunning) pw.println("Backup currently running");
   9192             pw.println("Last backup pass started: " + mLastBackupPass
   9193                     + " (now = " + System.currentTimeMillis() + ')');
   9194             pw.println("  next scheduled: " + mNextBackupPass);
   9195 
   9196             pw.println("Available transports:");
   9197             final String[] transports = listAllTransports();
   9198             if (transports != null) {
   9199                 for (String t : listAllTransports()) {
   9200                     pw.println((t.equals(mCurrentTransport) ? "  * " : "    ") + t);
   9201                     try {
   9202                         IBackupTransport transport = getTransport(t);
   9203                         File dir = new File(mBaseStateDir, transport.transportDirName());
   9204                         pw.println("       destination: " + transport.currentDestinationString());
   9205                         pw.println("       intent: " + transport.configurationIntent());
   9206                         for (File f : dir.listFiles()) {
   9207                             pw.println("       " + f.getName() + " - " + f.length() + " state bytes");
   9208                         }
   9209                     } catch (Exception e) {
   9210                         Slog.e(TAG, "Error in transport", e);
   9211                         pw.println("        Error: " + e);
   9212                     }
   9213                 }
   9214             }
   9215 
   9216             pw.println("Pending init: " + mPendingInits.size());
   9217             for (String s : mPendingInits) {
   9218                 pw.println("    " + s);
   9219             }
   9220 
   9221             if (DEBUG_BACKUP_TRACE) {
   9222                 synchronized (mBackupTrace) {
   9223                     if (!mBackupTrace.isEmpty()) {
   9224                         pw.println("Most recent backup trace:");
   9225                         for (String s : mBackupTrace) {
   9226                             pw.println("   " + s);
   9227                         }
   9228                     }
   9229                 }
   9230             }
   9231 
   9232             int N = mBackupParticipants.size();
   9233             pw.println("Participants:");
   9234             for (int i=0; i<N; i++) {
   9235                 int uid = mBackupParticipants.keyAt(i);
   9236                 pw.print("  uid: ");
   9237                 pw.println(uid);
   9238                 HashSet<String> participants = mBackupParticipants.valueAt(i);
   9239                 for (String app: participants) {
   9240                     pw.println("    " + app);
   9241                 }
   9242             }
   9243 
   9244             pw.println("Ancestral packages: "
   9245                     + (mAncestralPackages == null ? "none" : mAncestralPackages.size()));
   9246             if (mAncestralPackages != null) {
   9247                 for (String pkg : mAncestralPackages) {
   9248                     pw.println("    " + pkg);
   9249                 }
   9250             }
   9251 
   9252             pw.println("Ever backed up: " + mEverStoredApps.size());
   9253             for (String pkg : mEverStoredApps) {
   9254                 pw.println("    " + pkg);
   9255             }
   9256 
   9257             pw.println("Pending key/value backup: " + mPendingBackups.size());
   9258             for (BackupRequest req : mPendingBackups.values()) {
   9259                 pw.println("    " + req);
   9260             }
   9261 
   9262             pw.println("Full backup queue:" + mFullBackupQueue.size());
   9263             for (FullBackupEntry entry : mFullBackupQueue) {
   9264                 pw.print("    "); pw.print(entry.lastBackup);
   9265                 pw.print(" : "); pw.println(entry.packageName);
   9266             }
   9267         }
   9268     }
   9269 }
   9270