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