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