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