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