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