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