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