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