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