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