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