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