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