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