BackupManagerService.java revision cd777e95a77ba0035566088a5432aa28a409e7d1
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.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
1869                return bindTransport(info);
1870            } else {
1871                Slog.w(TAG, "Transport package " + info.packageName + " not privileged");
1872            }
1873        } catch (NameNotFoundException e) {
1874            Slog.w(TAG, "Problem resolving transport package " + info.packageName);
1875        }
1876        return false;
1877    }
1878
1879    // Actually bind; presumes that we have already validated the transport service
1880    boolean bindTransport(ServiceInfo transport) {
1881        ComponentName svcName = new ComponentName(transport.packageName, transport.name);
1882        if (DEBUG) {
1883            Slog.i(TAG, "Binding to transport host " + svcName);
1884        }
1885        Intent intent = new Intent(mTransportServiceIntent);
1886        intent.setComponent(svcName);
1887
1888        TransportConnection connection;
1889        synchronized (mTransports) {
1890            connection = mTransportConnections.get(transport.packageName);
1891            if (null == connection) {
1892                connection = new TransportConnection(transport);
1893                mTransportConnections.put(transport.packageName, connection);
1894            } else {
1895                // This is a rebind due to package upgrade.  The service won't be
1896                // automatically relaunched for us until we explicitly rebind, but
1897                // we need to unbind the now-orphaned original connection.
1898                mContext.unbindService(connection);
1899            }
1900        }
1901        return mContext.bindServiceAsUser(intent,
1902                connection, Context.BIND_AUTO_CREATE,
1903                UserHandle.OWNER);
1904    }
1905
1906    // Add the backup agents in the given packages to our set of known backup participants.
1907    // If 'packageNames' is null, adds all backup agents in the whole system.
1908    void addPackageParticipantsLocked(String[] packageNames) {
1909        // Look for apps that define the android:backupAgent attribute
1910        List<PackageInfo> targetApps = allAgentPackages();
1911        if (packageNames != null) {
1912            if (MORE_DEBUG) Slog.v(TAG, "addPackageParticipantsLocked: #" + packageNames.length);
1913            for (String packageName : packageNames) {
1914                addPackageParticipantsLockedInner(packageName, targetApps);
1915            }
1916        } else {
1917            if (MORE_DEBUG) Slog.v(TAG, "addPackageParticipantsLocked: all");
1918            addPackageParticipantsLockedInner(null, targetApps);
1919        }
1920    }
1921
1922    private void addPackageParticipantsLockedInner(String packageName,
1923            List<PackageInfo> targetPkgs) {
1924        if (MORE_DEBUG) {
1925            Slog.v(TAG, "Examining " + packageName + " for backup agent");
1926        }
1927
1928        for (PackageInfo pkg : targetPkgs) {
1929            if (packageName == null || pkg.packageName.equals(packageName)) {
1930                int uid = pkg.applicationInfo.uid;
1931                HashSet<String> set = mBackupParticipants.get(uid);
1932                if (set == null) {
1933                    set = new HashSet<String>();
1934                    mBackupParticipants.put(uid, set);
1935                }
1936                set.add(pkg.packageName);
1937                if (MORE_DEBUG) Slog.v(TAG, "Agent found; added");
1938
1939                // Schedule a backup for it on general principles
1940                if (MORE_DEBUG) Slog.i(TAG, "Scheduling backup for new app " + pkg.packageName);
1941                dataChangedImpl(pkg.packageName);
1942            }
1943        }
1944    }
1945
1946    // Remove the given packages' entries from our known active set.
1947    void removePackageParticipantsLocked(String[] packageNames, int oldUid) {
1948        if (packageNames == null) {
1949            Slog.w(TAG, "removePackageParticipants with null list");
1950            return;
1951        }
1952
1953        if (MORE_DEBUG) Slog.v(TAG, "removePackageParticipantsLocked: uid=" + oldUid
1954                + " #" + packageNames.length);
1955        for (String pkg : packageNames) {
1956            // Known previous UID, so we know which package set to check
1957            HashSet<String> set = mBackupParticipants.get(oldUid);
1958            if (set != null && set.contains(pkg)) {
1959                removePackageFromSetLocked(set, pkg);
1960                if (set.isEmpty()) {
1961                    if (MORE_DEBUG) Slog.v(TAG, "  last one of this uid; purging set");
1962                    mBackupParticipants.remove(oldUid);
1963                }
1964            }
1965        }
1966    }
1967
1968    private void removePackageFromSetLocked(final HashSet<String> set,
1969            final String packageName) {
1970        if (set.contains(packageName)) {
1971            // Found it.  Remove this one package from the bookkeeping, and
1972            // if it's the last participating app under this uid we drop the
1973            // (now-empty) set as well.
1974            // Note that we deliberately leave it 'known' in the "ever backed up"
1975            // bookkeeping so that its current-dataset data will be retrieved
1976            // if the app is subsequently reinstalled
1977            if (MORE_DEBUG) Slog.v(TAG, "  removing participant " + packageName);
1978            set.remove(packageName);
1979            mPendingBackups.remove(packageName);
1980        }
1981    }
1982
1983    // Returns the set of all applications that define an android:backupAgent attribute
1984    List<PackageInfo> allAgentPackages() {
1985        // !!! TODO: cache this and regenerate only when necessary
1986        int flags = PackageManager.GET_SIGNATURES;
1987        List<PackageInfo> packages = mPackageManager.getInstalledPackages(flags);
1988        int N = packages.size();
1989        for (int a = N-1; a >= 0; a--) {
1990            PackageInfo pkg = packages.get(a);
1991            try {
1992                ApplicationInfo app = pkg.applicationInfo;
1993                if (((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0)
1994                        || app.backupAgentName == null) {
1995                    packages.remove(a);
1996                }
1997                else {
1998                    // we will need the shared library path, so look that up and store it here.
1999                    // This is used implicitly when we pass the PackageInfo object off to
2000                    // the Activity Manager to launch the app for backup/restore purposes.
2001                    app = mPackageManager.getApplicationInfo(pkg.packageName,
2002                            PackageManager.GET_SHARED_LIBRARY_FILES);
2003                    pkg.applicationInfo.sharedLibraryFiles = app.sharedLibraryFiles;
2004                }
2005            } catch (NameNotFoundException e) {
2006                packages.remove(a);
2007            }
2008        }
2009        return packages;
2010    }
2011
2012    // Called from the backup tasks: record that the given app has been successfully
2013    // backed up at least once.  This includes both key/value and full-data backups
2014    // through the transport.
2015    void logBackupComplete(String packageName) {
2016        if (packageName.equals(PACKAGE_MANAGER_SENTINEL)) return;
2017
2018        synchronized (mEverStoredApps) {
2019            if (!mEverStoredApps.add(packageName)) return;
2020
2021            RandomAccessFile out = null;
2022            try {
2023                out = new RandomAccessFile(mEverStored, "rws");
2024                out.seek(out.length());
2025                out.writeUTF(packageName);
2026            } catch (IOException e) {
2027                Slog.e(TAG, "Can't log backup of " + packageName + " to " + mEverStored);
2028            } finally {
2029                try { if (out != null) out.close(); } catch (IOException e) {}
2030            }
2031        }
2032    }
2033
2034    // Remove our awareness of having ever backed up the given package
2035    void removeEverBackedUp(String packageName) {
2036        if (DEBUG) Slog.v(TAG, "Removing backed-up knowledge of " + packageName);
2037        if (MORE_DEBUG) Slog.v(TAG, "New set:");
2038
2039        synchronized (mEverStoredApps) {
2040            // Rewrite the file and rename to overwrite.  If we reboot in the middle,
2041            // we'll recognize on initialization time that the package no longer
2042            // exists and fix it up then.
2043            File tempKnownFile = new File(mBaseStateDir, "processed.new");
2044            RandomAccessFile known = null;
2045            try {
2046                known = new RandomAccessFile(tempKnownFile, "rws");
2047                mEverStoredApps.remove(packageName);
2048                for (String s : mEverStoredApps) {
2049                    known.writeUTF(s);
2050                    if (MORE_DEBUG) Slog.v(TAG, "    " + s);
2051                }
2052                known.close();
2053                known = null;
2054                if (!tempKnownFile.renameTo(mEverStored)) {
2055                    throw new IOException("Can't rename " + tempKnownFile + " to " + mEverStored);
2056                }
2057            } catch (IOException e) {
2058                // Bad: we couldn't create the new copy.  For safety's sake we
2059                // abandon the whole process and remove all what's-backed-up
2060                // state entirely, meaning we'll force a backup pass for every
2061                // participant on the next boot or [re]install.
2062                Slog.w(TAG, "Error rewriting " + mEverStored, e);
2063                mEverStoredApps.clear();
2064                tempKnownFile.delete();
2065                mEverStored.delete();
2066            } finally {
2067                try { if (known != null) known.close(); } catch (IOException e) {}
2068            }
2069        }
2070    }
2071
2072    // Persistently record the current and ancestral backup tokens as well
2073    // as the set of packages with data [supposedly] available in the
2074    // ancestral dataset.
2075    void writeRestoreTokens() {
2076        try {
2077            RandomAccessFile af = new RandomAccessFile(mTokenFile, "rwd");
2078
2079            // First, the version number of this record, for futureproofing
2080            af.writeInt(CURRENT_ANCESTRAL_RECORD_VERSION);
2081
2082            // Write the ancestral and current tokens
2083            af.writeLong(mAncestralToken);
2084            af.writeLong(mCurrentToken);
2085
2086            // Now write the set of ancestral packages
2087            if (mAncestralPackages == null) {
2088                af.writeInt(-1);
2089            } else {
2090                af.writeInt(mAncestralPackages.size());
2091                if (DEBUG) Slog.v(TAG, "Ancestral packages:  " + mAncestralPackages.size());
2092                for (String pkgName : mAncestralPackages) {
2093                    af.writeUTF(pkgName);
2094                    if (MORE_DEBUG) Slog.v(TAG, "   " + pkgName);
2095                }
2096            }
2097            af.close();
2098        } catch (IOException e) {
2099            Slog.w(TAG, "Unable to write token file:", e);
2100        }
2101    }
2102
2103    // Return the given transport
2104    private IBackupTransport getTransport(String transportName) {
2105        synchronized (mTransports) {
2106            IBackupTransport transport = mTransports.get(transportName);
2107            if (transport == null) {
2108                Slog.w(TAG, "Requested unavailable transport: " + transportName);
2109            }
2110            return transport;
2111        }
2112    }
2113
2114    // fire off a backup agent, blocking until it attaches or times out
2115    IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode) {
2116        IBackupAgent agent = null;
2117        synchronized(mAgentConnectLock) {
2118            mConnecting = true;
2119            mConnectedAgent = null;
2120            try {
2121                if (mActivityManager.bindBackupAgent(app.packageName, mode,
2122                        UserHandle.USER_OWNER)) {
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            // Okay, the agent successfully reported back to us!
2782            final String pkgName = mCurrentPackage.packageName;
2783            final long filepos = mBackupDataName.length();
2784            FileDescriptor fd = mBackupData.getFileDescriptor();
2785            try {
2786                // If it's a 3rd party app, see whether they wrote any protected keys
2787                // and complain mightily if they are attempting shenanigans.
2788                if (mCurrentPackage.applicationInfo != null &&
2789                        (mCurrentPackage.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
2790                    ParcelFileDescriptor readFd = ParcelFileDescriptor.open(mBackupDataName,
2791                            ParcelFileDescriptor.MODE_READ_ONLY);
2792                    BackupDataInput in = new BackupDataInput(readFd.getFileDescriptor());
2793                    try {
2794                        while (in.readNextHeader()) {
2795                            final String key = in.getKey();
2796                            if (key != null && key.charAt(0) >= 0xff00) {
2797                                // Not okay: crash them and bail.
2798                                failAgent(mAgentBinder, "Illegal backup key: " + key);
2799                                addBackupTrace("illegal key " + key + " from " + pkgName);
2800                                EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, pkgName,
2801                                        "bad key");
2802                                mBackupHandler.removeMessages(MSG_TIMEOUT);
2803                                agentErrorCleanup();
2804                                // agentErrorCleanup() implicitly executes next state properly
2805                                return;
2806                            }
2807                            in.skipEntityData();
2808                        }
2809                    } finally {
2810                        if (readFd != null) {
2811                            readFd.close();
2812                        }
2813                    }
2814                }
2815
2816                // Piggyback the widget state payload, if any
2817                writeWidgetPayloadIfAppropriate(fd, pkgName);
2818            } catch (IOException e) {
2819                // Hard disk error; recovery/failure policy TBD.  For now roll back,
2820                // but we may want to consider this a transport-level failure (i.e.
2821                // we're in such a bad state that we can't contemplate doing backup
2822                // operations any more during this pass).
2823                Slog.w(TAG, "Unable to save widget state for " + pkgName);
2824                try {
2825                    Os.ftruncate(fd, filepos);
2826                } catch (ErrnoException ee) {
2827                    Slog.w(TAG, "Unable to roll back!");
2828                }
2829            }
2830
2831            // Spin the data off to the transport and proceed with the next stage.
2832            if (MORE_DEBUG) Slog.v(TAG, "operationComplete(): sending data to transport for "
2833                    + pkgName);
2834            mBackupHandler.removeMessages(MSG_TIMEOUT);
2835            clearAgentState();
2836            addBackupTrace("operation complete");
2837
2838            ParcelFileDescriptor backupData = null;
2839            mStatus = BackupTransport.TRANSPORT_OK;
2840            try {
2841                int size = (int) mBackupDataName.length();
2842                if (size > 0) {
2843                    if (mStatus == BackupTransport.TRANSPORT_OK) {
2844                        backupData = ParcelFileDescriptor.open(mBackupDataName,
2845                                ParcelFileDescriptor.MODE_READ_ONLY);
2846                        addBackupTrace("sending data to transport");
2847                        mStatus = mTransport.performBackup(mCurrentPackage, backupData);
2848                    }
2849
2850                    // TODO - We call finishBackup() for each application backed up, because
2851                    // we need to know now whether it succeeded or failed.  Instead, we should
2852                    // hold off on finishBackup() until the end, which implies holding off on
2853                    // renaming *all* the output state files (see below) until that happens.
2854
2855                    addBackupTrace("data delivered: " + mStatus);
2856                    if (mStatus == BackupTransport.TRANSPORT_OK) {
2857                        addBackupTrace("finishing op on transport");
2858                        mStatus = mTransport.finishBackup();
2859                        addBackupTrace("finished: " + mStatus);
2860                    } else if (mStatus == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
2861                        addBackupTrace("transport rejected package");
2862                    }
2863                } else {
2864                    if (DEBUG) Slog.i(TAG, "no backup data written; not calling transport");
2865                    addBackupTrace("no data to send");
2866                }
2867
2868                if (mStatus == BackupTransport.TRANSPORT_OK) {
2869                    // After successful transport, delete the now-stale data
2870                    // and juggle the files so that next time we supply the agent
2871                    // with the new state file it just created.
2872                    mBackupDataName.delete();
2873                    mNewStateName.renameTo(mSavedStateName);
2874                    EventLog.writeEvent(EventLogTags.BACKUP_PACKAGE, pkgName, size);
2875                    logBackupComplete(pkgName);
2876                } else if (mStatus == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
2877                    // The transport has rejected backup of this specific package.  Roll it
2878                    // back but proceed with running the rest of the queue.
2879                    mBackupDataName.delete();
2880                    mNewStateName.delete();
2881                    EventLogTags.writeBackupAgentFailure(pkgName, "Transport rejected");
2882                } else {
2883                    // Actual transport-level failure to communicate the data to the backend
2884                    EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, pkgName);
2885                }
2886            } catch (Exception e) {
2887                Slog.e(TAG, "Transport error backing up " + pkgName, e);
2888                EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, pkgName);
2889                mStatus = BackupTransport.TRANSPORT_ERROR;
2890            } finally {
2891                try { if (backupData != null) backupData.close(); } catch (IOException e) {}
2892            }
2893
2894            final BackupState nextState;
2895            if (mStatus == BackupTransport.TRANSPORT_OK
2896                    || mStatus == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
2897                // Success or single-package rejection.  Proceed with the next app if any,
2898                // otherwise we're done.
2899                nextState = (mQueue.isEmpty()) ? BackupState.FINAL : BackupState.RUNNING_QUEUE;
2900            } else {
2901                // Any other error here indicates a transport-level failure.  That means
2902                // we need to halt everything and reschedule everything for next time.
2903                revertAndEndBackup();
2904                nextState = BackupState.FINAL;
2905            }
2906
2907            executeNextState(nextState);
2908        }
2909
2910        @Override
2911        public void handleTimeout() {
2912            // Whoops, the current agent timed out running doBackup().  Tidy up and restage
2913            // it for the next time we run a backup pass.
2914            // !!! TODO: keep track of failure counts per agent, and blacklist those which
2915            // fail repeatedly (i.e. have proved themselves to be buggy).
2916            Slog.e(TAG, "Timeout backing up " + mCurrentPackage.packageName);
2917            EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, mCurrentPackage.packageName,
2918                    "timeout");
2919            addBackupTrace("timeout of " + mCurrentPackage.packageName);
2920            agentErrorCleanup();
2921            dataChangedImpl(mCurrentPackage.packageName);
2922        }
2923
2924        void revertAndEndBackup() {
2925            if (MORE_DEBUG) Slog.i(TAG, "Reverting backup queue - restaging everything");
2926            addBackupTrace("transport error; reverting");
2927            for (BackupRequest request : mOriginalQueue) {
2928                dataChangedImpl(request.packageName);
2929            }
2930            // We also want to reset the backup schedule based on whatever
2931            // the transport suggests by way of retry/backoff time.
2932            restartBackupAlarm();
2933        }
2934
2935        void agentErrorCleanup() {
2936            mBackupDataName.delete();
2937            mNewStateName.delete();
2938            clearAgentState();
2939
2940            executeNextState(mQueue.isEmpty() ? BackupState.FINAL : BackupState.RUNNING_QUEUE);
2941        }
2942
2943        // Cleanup common to both success and failure cases
2944        void clearAgentState() {
2945            try { if (mSavedState != null) mSavedState.close(); } catch (IOException e) {}
2946            try { if (mBackupData != null) mBackupData.close(); } catch (IOException e) {}
2947            try { if (mNewState != null) mNewState.close(); } catch (IOException e) {}
2948            synchronized (mCurrentOpLock) {
2949                // Current-operation callback handling requires the validity of these various
2950                // bits of internal state as an invariant of the operation still being live.
2951                // This means we make sure to clear all of the state in unison inside the lock.
2952                mCurrentOperations.clear();
2953                mSavedState = mBackupData = mNewState = null;
2954            }
2955
2956            // If this was a pseudopackage there's no associated Activity Manager state
2957            if (mCurrentPackage.applicationInfo != null) {
2958                addBackupTrace("unbinding " + mCurrentPackage.packageName);
2959                try {  // unbind even on timeout, just in case
2960                    mActivityManager.unbindBackupAgent(mCurrentPackage.applicationInfo);
2961                } catch (RemoteException e) { /* can't happen; activity manager is local */ }
2962            }
2963        }
2964
2965        void restartBackupAlarm() {
2966            addBackupTrace("setting backup trigger");
2967            synchronized (mQueueLock) {
2968                try {
2969                    startBackupAlarmsLocked(mTransport.requestBackupTime());
2970                } catch (RemoteException e) { /* cannot happen */ }
2971            }
2972        }
2973
2974        void executeNextState(BackupState nextState) {
2975            if (MORE_DEBUG) Slog.i(TAG, " => executing next step on "
2976                    + this + " nextState=" + nextState);
2977            addBackupTrace("executeNextState => " + nextState);
2978            mCurrentState = nextState;
2979            Message msg = mBackupHandler.obtainMessage(MSG_BACKUP_RESTORE_STEP, this);
2980            mBackupHandler.sendMessage(msg);
2981        }
2982    }
2983
2984
2985    // ----- Full backup/restore to a file/socket -----
2986
2987    class FullBackupObbConnection implements ServiceConnection {
2988        volatile IObbBackupService mService;
2989
2990        FullBackupObbConnection() {
2991            mService = null;
2992        }
2993
2994        public void establish() {
2995            if (DEBUG) Slog.i(TAG, "Initiating bind of OBB service on " + this);
2996            Intent obbIntent = new Intent().setComponent(new ComponentName(
2997                    "com.android.sharedstoragebackup",
2998                    "com.android.sharedstoragebackup.ObbBackupService"));
2999            BackupManagerService.this.mContext.bindService(
3000                    obbIntent, this, Context.BIND_AUTO_CREATE);
3001        }
3002
3003        public void tearDown() {
3004            BackupManagerService.this.mContext.unbindService(this);
3005        }
3006
3007        public boolean backupObbs(PackageInfo pkg, OutputStream out) {
3008            boolean success = false;
3009            waitForConnection();
3010
3011            ParcelFileDescriptor[] pipes = null;
3012            try {
3013                pipes = ParcelFileDescriptor.createPipe();
3014                int token = generateToken();
3015                prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL, null);
3016                mService.backupObbs(pkg.packageName, pipes[1], token, mBackupManagerBinder);
3017                routeSocketDataToOutput(pipes[0], out);
3018                success = waitUntilOperationComplete(token);
3019            } catch (Exception e) {
3020                Slog.w(TAG, "Unable to back up OBBs for " + pkg, e);
3021            } finally {
3022                try {
3023                    out.flush();
3024                    if (pipes != null) {
3025                        if (pipes[0] != null) pipes[0].close();
3026                        if (pipes[1] != null) pipes[1].close();
3027                    }
3028                } catch (IOException e) {
3029                    Slog.w(TAG, "I/O error closing down OBB backup", e);
3030                }
3031            }
3032            return success;
3033        }
3034
3035        public void restoreObbFile(String pkgName, ParcelFileDescriptor data,
3036                long fileSize, int type, String path, long mode, long mtime,
3037                int token, IBackupManager callbackBinder) {
3038            waitForConnection();
3039
3040            try {
3041                mService.restoreObbFile(pkgName, data, fileSize, type, path, mode, mtime,
3042                        token, callbackBinder);
3043            } catch (Exception e) {
3044                Slog.w(TAG, "Unable to restore OBBs for " + pkgName, e);
3045            }
3046        }
3047
3048        private void waitForConnection() {
3049            synchronized (this) {
3050                while (mService == null) {
3051                    if (DEBUG) Slog.i(TAG, "...waiting for OBB service binding...");
3052                    try {
3053                        this.wait();
3054                    } catch (InterruptedException e) { /* never interrupted */ }
3055                }
3056                if (DEBUG) Slog.i(TAG, "Connected to OBB service; continuing");
3057            }
3058        }
3059
3060        @Override
3061        public void onServiceConnected(ComponentName name, IBinder service) {
3062            synchronized (this) {
3063                mService = IObbBackupService.Stub.asInterface(service);
3064                if (DEBUG) Slog.i(TAG, "OBB service connection " + mService
3065                        + " connected on " + this);
3066                this.notifyAll();
3067            }
3068        }
3069
3070        @Override
3071        public void onServiceDisconnected(ComponentName name) {
3072            synchronized (this) {
3073                mService = null;
3074                if (DEBUG) Slog.i(TAG, "OBB service connection disconnected on " + this);
3075                this.notifyAll();
3076            }
3077        }
3078
3079    }
3080
3081    private void routeSocketDataToOutput(ParcelFileDescriptor inPipe, OutputStream out)
3082            throws IOException {
3083        FileInputStream raw = new FileInputStream(inPipe.getFileDescriptor());
3084        DataInputStream in = new DataInputStream(raw);
3085
3086        byte[] buffer = new byte[32 * 1024];
3087        int chunkTotal;
3088        while ((chunkTotal = in.readInt()) > 0) {
3089            while (chunkTotal > 0) {
3090                int toRead = (chunkTotal > buffer.length) ? buffer.length : chunkTotal;
3091                int nRead = in.read(buffer, 0, toRead);
3092                out.write(buffer, 0, nRead);
3093                chunkTotal -= nRead;
3094            }
3095        }
3096    }
3097
3098    // Core logic for performing one package's full backup, gathering the tarball from the
3099    // application and emitting it to the designated OutputStream.
3100    class FullBackupEngine {
3101        OutputStream mOutput;
3102        IFullBackupRestoreObserver mObserver;
3103        File mFilesDir;
3104        File mManifestFile;
3105        File mMetadataFile;
3106        boolean mIncludeApks;
3107
3108        class FullBackupRunner implements Runnable {
3109            PackageInfo mPackage;
3110            byte[] mWidgetData;
3111            IBackupAgent mAgent;
3112            ParcelFileDescriptor mPipe;
3113            int mToken;
3114            boolean mSendApk;
3115            boolean mWriteManifest;
3116
3117            FullBackupRunner(PackageInfo pack, IBackupAgent agent, ParcelFileDescriptor pipe,
3118                    int token, boolean sendApk, boolean writeManifest, byte[] widgetData)
3119                            throws IOException {
3120                mPackage = pack;
3121                mWidgetData = widgetData;
3122                mAgent = agent;
3123                mPipe = ParcelFileDescriptor.dup(pipe.getFileDescriptor());
3124                mToken = token;
3125                mSendApk = sendApk;
3126                mWriteManifest = writeManifest;
3127            }
3128
3129            @Override
3130            public void run() {
3131                try {
3132                    BackupDataOutput output = new BackupDataOutput(
3133                            mPipe.getFileDescriptor());
3134
3135                    if (mWriteManifest) {
3136                        final boolean writeWidgetData = mWidgetData != null;
3137                        if (MORE_DEBUG) Slog.d(TAG, "Writing manifest for " + mPackage.packageName);
3138                        writeAppManifest(mPackage, mManifestFile, mSendApk, writeWidgetData);
3139                        FullBackup.backupToTar(mPackage.packageName, null, null,
3140                                mFilesDir.getAbsolutePath(),
3141                                mManifestFile.getAbsolutePath(),
3142                                output);
3143                        mManifestFile.delete();
3144
3145                        // We only need to write a metadata file if we have widget data to stash
3146                        if (writeWidgetData) {
3147                            writeMetadata(mPackage, mMetadataFile, mWidgetData);
3148                            FullBackup.backupToTar(mPackage.packageName, null, null,
3149                                    mFilesDir.getAbsolutePath(),
3150                                    mMetadataFile.getAbsolutePath(),
3151                                    output);
3152                            mMetadataFile.delete();
3153                        }
3154                    }
3155
3156                    if (mSendApk) {
3157                        writeApkToBackup(mPackage, output);
3158                    }
3159
3160                    if (DEBUG) Slog.d(TAG, "Calling doFullBackup() on " + mPackage.packageName);
3161                    prepareOperationTimeout(mToken, TIMEOUT_FULL_BACKUP_INTERVAL, null);
3162                    mAgent.doFullBackup(mPipe, mToken, mBackupManagerBinder);
3163                } catch (IOException e) {
3164                    Slog.e(TAG, "Error running full backup for " + mPackage.packageName);
3165                } catch (RemoteException e) {
3166                    Slog.e(TAG, "Remote agent vanished during full backup of "
3167                            + mPackage.packageName);
3168                } finally {
3169                    try {
3170                        mPipe.close();
3171                    } catch (IOException e) {}
3172                }
3173            }
3174        }
3175
3176        FullBackupEngine(OutputStream output, String packageName, boolean alsoApks) {
3177            mOutput = output;
3178            mIncludeApks = alsoApks;
3179            mFilesDir = new File("/data/system");
3180            mManifestFile = new File(mFilesDir, BACKUP_MANIFEST_FILENAME);
3181            mMetadataFile = new File(mFilesDir, BACKUP_METADATA_FILENAME);
3182        }
3183
3184
3185        public int backupOnePackage(PackageInfo pkg) throws RemoteException {
3186            int result = BackupTransport.TRANSPORT_OK;
3187            Slog.d(TAG, "Binding to full backup agent : " + pkg.packageName);
3188
3189            IBackupAgent agent = bindToAgentSynchronous(pkg.applicationInfo,
3190                    IApplicationThread.BACKUP_MODE_FULL);
3191            if (agent != null) {
3192                ParcelFileDescriptor[] pipes = null;
3193                try {
3194                    pipes = ParcelFileDescriptor.createPipe();
3195
3196                    ApplicationInfo app = pkg.applicationInfo;
3197                    final boolean isSharedStorage = pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE);
3198                    final boolean sendApk = mIncludeApks
3199                            && !isSharedStorage
3200                            && ((app.flags & ApplicationInfo.FLAG_FORWARD_LOCK) == 0)
3201                            && ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0 ||
3202                                (app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
3203
3204                    byte[] widgetBlob = AppWidgetBackupBridge.getWidgetState(pkg.packageName,
3205                            UserHandle.USER_OWNER);
3206
3207                    final int token = generateToken();
3208                    FullBackupRunner runner = new FullBackupRunner(pkg, agent, pipes[1],
3209                            token, sendApk, !isSharedStorage, widgetBlob);
3210                    pipes[1].close();   // the runner has dup'd it
3211                    pipes[1] = null;
3212                    Thread t = new Thread(runner, "app-data-runner");
3213                    t.start();
3214
3215                    // Now pull data from the app and stuff it into the output
3216                    try {
3217                        routeSocketDataToOutput(pipes[0], mOutput);
3218                    } catch (IOException e) {
3219                        Slog.i(TAG, "Caught exception reading from agent", e);
3220                        result = BackupTransport.AGENT_ERROR;
3221                    }
3222
3223                    if (!waitUntilOperationComplete(token)) {
3224                        Slog.e(TAG, "Full backup failed on package " + pkg.packageName);
3225                        result = BackupTransport.AGENT_ERROR;
3226                    } else {
3227                        if (DEBUG) Slog.d(TAG, "Full package backup success: " + pkg.packageName);
3228                    }
3229
3230                } catch (IOException e) {
3231                    Slog.e(TAG, "Error backing up " + pkg.packageName, e);
3232                    result = BackupTransport.AGENT_ERROR;
3233                } finally {
3234                    try {
3235                        // flush after every package
3236                        mOutput.flush();
3237                        if (pipes != null) {
3238                            if (pipes[0] != null) pipes[0].close();
3239                            if (pipes[1] != null) pipes[1].close();
3240                        }
3241                    } catch (IOException e) {
3242                        Slog.w(TAG, "Error bringing down backup stack");
3243                        result = BackupTransport.TRANSPORT_ERROR;
3244                    }
3245                }
3246            } else {
3247                Slog.w(TAG, "Unable to bind to full agent for " + pkg.packageName);
3248                result = BackupTransport.AGENT_ERROR;
3249            }
3250            tearDown(pkg);
3251            return result;
3252        }
3253
3254        private void writeApkToBackup(PackageInfo pkg, BackupDataOutput output) {
3255            // Forward-locked apps, system-bundled .apks, etc are filtered out before we get here
3256            // TODO: handle backing up split APKs
3257            final String appSourceDir = pkg.applicationInfo.getBaseCodePath();
3258            final String apkDir = new File(appSourceDir).getParent();
3259            FullBackup.backupToTar(pkg.packageName, FullBackup.APK_TREE_TOKEN, null,
3260                    apkDir, appSourceDir, output);
3261
3262            // TODO: migrate this to SharedStorageBackup, since AID_SYSTEM
3263            // doesn't have access to external storage.
3264
3265            // Save associated .obb content if it exists and we did save the apk
3266            // check for .obb and save those too
3267            final UserEnvironment userEnv = new UserEnvironment(UserHandle.USER_OWNER);
3268            final File obbDir = userEnv.buildExternalStorageAppObbDirs(pkg.packageName)[0];
3269            if (obbDir != null) {
3270                if (MORE_DEBUG) Log.i(TAG, "obb dir: " + obbDir.getAbsolutePath());
3271                File[] obbFiles = obbDir.listFiles();
3272                if (obbFiles != null) {
3273                    final String obbDirName = obbDir.getAbsolutePath();
3274                    for (File obb : obbFiles) {
3275                        FullBackup.backupToTar(pkg.packageName, FullBackup.OBB_TREE_TOKEN, null,
3276                                obbDirName, obb.getAbsolutePath(), output);
3277                    }
3278                }
3279            }
3280        }
3281
3282        private void writeAppManifest(PackageInfo pkg, File manifestFile,
3283                boolean withApk, boolean withWidgets) throws IOException {
3284            // Manifest format. All data are strings ending in LF:
3285            //     BACKUP_MANIFEST_VERSION, currently 1
3286            //
3287            // Version 1:
3288            //     package name
3289            //     package's versionCode
3290            //     platform versionCode
3291            //     getInstallerPackageName() for this package (maybe empty)
3292            //     boolean: "1" if archive includes .apk; any other string means not
3293            //     number of signatures == N
3294            // N*:    signature byte array in ascii format per Signature.toCharsString()
3295            StringBuilder builder = new StringBuilder(4096);
3296            StringBuilderPrinter printer = new StringBuilderPrinter(builder);
3297
3298            printer.println(Integer.toString(BACKUP_MANIFEST_VERSION));
3299            printer.println(pkg.packageName);
3300            printer.println(Integer.toString(pkg.versionCode));
3301            printer.println(Integer.toString(Build.VERSION.SDK_INT));
3302
3303            String installerName = mPackageManager.getInstallerPackageName(pkg.packageName);
3304            printer.println((installerName != null) ? installerName : "");
3305
3306            printer.println(withApk ? "1" : "0");
3307            if (pkg.signatures == null) {
3308                printer.println("0");
3309            } else {
3310                printer.println(Integer.toString(pkg.signatures.length));
3311                for (Signature sig : pkg.signatures) {
3312                    printer.println(sig.toCharsString());
3313                }
3314            }
3315
3316            FileOutputStream outstream = new FileOutputStream(manifestFile);
3317            outstream.write(builder.toString().getBytes());
3318            outstream.close();
3319
3320            // We want the manifest block in the archive stream to be idempotent:
3321            // each time we generate a backup stream for the app, we want the manifest
3322            // block to be identical.  The underlying tar mechanism sees it as a file,
3323            // though, and will propagate its mtime, causing the tar header to vary.
3324            // Avoid this problem by pinning the mtime to zero.
3325            manifestFile.setLastModified(0);
3326        }
3327
3328        // Widget metadata format. All header entries are strings ending in LF:
3329        //
3330        // Version 1 header:
3331        //     BACKUP_METADATA_VERSION, currently "1"
3332        //     package name
3333        //
3334        // File data (all integers are binary in network byte order)
3335        // *N: 4 : integer token identifying which metadata blob
3336        //     4 : integer size of this blob = N
3337        //     N : raw bytes of this metadata blob
3338        //
3339        // Currently understood blobs (always in network byte order):
3340        //
3341        //     widgets : metadata token = 0x01FFED01 (BACKUP_WIDGET_METADATA_TOKEN)
3342        //
3343        // Unrecognized blobs are *ignored*, not errors.
3344        private void writeMetadata(PackageInfo pkg, File destination, byte[] widgetData)
3345                throws IOException {
3346            StringBuilder b = new StringBuilder(512);
3347            StringBuilderPrinter printer = new StringBuilderPrinter(b);
3348            printer.println(Integer.toString(BACKUP_METADATA_VERSION));
3349            printer.println(pkg.packageName);
3350
3351            FileOutputStream fout = new FileOutputStream(destination);
3352            BufferedOutputStream bout = new BufferedOutputStream(fout);
3353            DataOutputStream out = new DataOutputStream(bout);
3354            bout.write(b.toString().getBytes());    // bypassing DataOutputStream
3355
3356            if (widgetData != null && widgetData.length > 0) {
3357                out.writeInt(BACKUP_WIDGET_METADATA_TOKEN);
3358                out.writeInt(widgetData.length);
3359                out.write(widgetData);
3360            }
3361            bout.flush();
3362            out.close();
3363
3364            // As with the manifest file, guarantee idempotence of the archive metadata
3365            // for the widget block by using a fixed mtime on the transient file.
3366            destination.setLastModified(0);
3367        }
3368
3369        private void tearDown(PackageInfo pkg) {
3370            if (pkg != null) {
3371                final ApplicationInfo app = pkg.applicationInfo;
3372                if (app != null) {
3373                    try {
3374                        // unbind and tidy up even on timeout or failure, just in case
3375                        mActivityManager.unbindBackupAgent(app);
3376
3377                        // The agent was running with a stub Application object, so shut it down.
3378                        if (app.uid != Process.SYSTEM_UID
3379                                && app.uid != Process.PHONE_UID) {
3380                            if (MORE_DEBUG) Slog.d(TAG, "Backup complete, killing host process");
3381                            mActivityManager.killApplicationProcess(app.processName, app.uid);
3382                        } else {
3383                            if (MORE_DEBUG) Slog.d(TAG, "Not killing after backup: " + app.processName);
3384                        }
3385                    } catch (RemoteException e) {
3386                        Slog.d(TAG, "Lost app trying to shut down");
3387                    }
3388                }
3389            }
3390        }
3391    }
3392
3393    // Generic driver skeleton for full backup operations
3394    abstract class FullBackupTask implements Runnable {
3395        IFullBackupRestoreObserver mObserver;
3396
3397        FullBackupTask(IFullBackupRestoreObserver observer) {
3398            mObserver = observer;
3399        }
3400
3401        // wrappers for observer use
3402        final void sendStartBackup() {
3403            if (mObserver != null) {
3404                try {
3405                    mObserver.onStartBackup();
3406                } catch (RemoteException e) {
3407                    Slog.w(TAG, "full backup observer went away: startBackup");
3408                    mObserver = null;
3409                }
3410            }
3411        }
3412
3413        final void sendOnBackupPackage(String name) {
3414            if (mObserver != null) {
3415                try {
3416                    // TODO: use a more user-friendly name string
3417                    mObserver.onBackupPackage(name);
3418                } catch (RemoteException e) {
3419                    Slog.w(TAG, "full backup observer went away: backupPackage");
3420                    mObserver = null;
3421                }
3422            }
3423        }
3424
3425        final void sendEndBackup() {
3426            if (mObserver != null) {
3427                try {
3428                    mObserver.onEndBackup();
3429                } catch (RemoteException e) {
3430                    Slog.w(TAG, "full backup observer went away: endBackup");
3431                    mObserver = null;
3432                }
3433            }
3434        }
3435    }
3436
3437    boolean deviceIsEncrypted() {
3438        try {
3439            return mMountService.getEncryptionState()
3440                     != IMountService.ENCRYPTION_STATE_NONE
3441                && mMountService.getPasswordType()
3442                     != StorageManager.CRYPT_TYPE_DEFAULT;
3443        } catch (Exception e) {
3444            // If we can't talk to the mount service we have a serious problem; fail
3445            // "secure" i.e. assuming that the device is encrypted.
3446            Slog.e(TAG, "Unable to communicate with mount service: " + e.getMessage());
3447            return true;
3448        }
3449    }
3450
3451    // Full backup task variant used for adb backup
3452    class PerformAdbBackupTask extends FullBackupTask {
3453        FullBackupEngine mBackupEngine;
3454        final AtomicBoolean mLatch;
3455
3456        ParcelFileDescriptor mOutputFile;
3457        DeflaterOutputStream mDeflater;
3458        boolean mIncludeApks;
3459        boolean mIncludeObbs;
3460        boolean mIncludeShared;
3461        boolean mDoWidgets;
3462        boolean mAllApps;
3463        boolean mIncludeSystem;
3464        boolean mCompress;
3465        ArrayList<String> mPackages;
3466        String mCurrentPassword;
3467        String mEncryptPassword;
3468
3469        PerformAdbBackupTask(ParcelFileDescriptor fd, IFullBackupRestoreObserver observer,
3470                boolean includeApks, boolean includeObbs, boolean includeShared,
3471                boolean doWidgets, String curPassword, String encryptPassword, boolean doAllApps,
3472                boolean doSystem, boolean doCompress, String[] packages, AtomicBoolean latch) {
3473            super(observer);
3474            mLatch = latch;
3475
3476            mOutputFile = fd;
3477            mIncludeApks = includeApks;
3478            mIncludeObbs = includeObbs;
3479            mIncludeShared = includeShared;
3480            mDoWidgets = doWidgets;
3481            mAllApps = doAllApps;
3482            mIncludeSystem = doSystem;
3483            mPackages = (packages == null)
3484                    ? new ArrayList<String>()
3485                    : new ArrayList<String>(Arrays.asList(packages));
3486            mCurrentPassword = curPassword;
3487            // when backing up, if there is a current backup password, we require that
3488            // the user use a nonempty encryption password as well.  if one is supplied
3489            // in the UI we use that, but if the UI was left empty we fall back to the
3490            // current backup password (which was supplied by the user as well).
3491            if (encryptPassword == null || "".equals(encryptPassword)) {
3492                mEncryptPassword = curPassword;
3493            } else {
3494                mEncryptPassword = encryptPassword;
3495            }
3496            mCompress = doCompress;
3497        }
3498
3499        void addPackagesToSet(TreeMap<String, PackageInfo> set, List<String> pkgNames) {
3500            for (String pkgName : pkgNames) {
3501                if (!set.containsKey(pkgName)) {
3502                    try {
3503                        PackageInfo info = mPackageManager.getPackageInfo(pkgName,
3504                                PackageManager.GET_SIGNATURES);
3505                        set.put(pkgName, info);
3506                    } catch (NameNotFoundException e) {
3507                        Slog.w(TAG, "Unknown package " + pkgName + ", skipping");
3508                    }
3509                }
3510            }
3511        }
3512
3513        private OutputStream emitAesBackupHeader(StringBuilder headerbuf,
3514                OutputStream ofstream) throws Exception {
3515            // User key will be used to encrypt the master key.
3516            byte[] newUserSalt = randomBytes(PBKDF2_SALT_SIZE);
3517            SecretKey userKey = buildPasswordKey(PBKDF_CURRENT, mEncryptPassword, newUserSalt,
3518                    PBKDF2_HASH_ROUNDS);
3519
3520            // the master key is random for each backup
3521            byte[] masterPw = new byte[256 / 8];
3522            mRng.nextBytes(masterPw);
3523            byte[] checksumSalt = randomBytes(PBKDF2_SALT_SIZE);
3524
3525            // primary encryption of the datastream with the random key
3526            Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
3527            SecretKeySpec masterKeySpec = new SecretKeySpec(masterPw, "AES");
3528            c.init(Cipher.ENCRYPT_MODE, masterKeySpec);
3529            OutputStream finalOutput = new CipherOutputStream(ofstream, c);
3530
3531            // line 4: name of encryption algorithm
3532            headerbuf.append(ENCRYPTION_ALGORITHM_NAME);
3533            headerbuf.append('\n');
3534            // line 5: user password salt [hex]
3535            headerbuf.append(byteArrayToHex(newUserSalt));
3536            headerbuf.append('\n');
3537            // line 6: master key checksum salt [hex]
3538            headerbuf.append(byteArrayToHex(checksumSalt));
3539            headerbuf.append('\n');
3540            // line 7: number of PBKDF2 rounds used [decimal]
3541            headerbuf.append(PBKDF2_HASH_ROUNDS);
3542            headerbuf.append('\n');
3543
3544            // line 8: IV of the user key [hex]
3545            Cipher mkC = Cipher.getInstance("AES/CBC/PKCS5Padding");
3546            mkC.init(Cipher.ENCRYPT_MODE, userKey);
3547
3548            byte[] IV = mkC.getIV();
3549            headerbuf.append(byteArrayToHex(IV));
3550            headerbuf.append('\n');
3551
3552            // line 9: master IV + key blob, encrypted by the user key [hex].  Blob format:
3553            //    [byte] IV length = Niv
3554            //    [array of Niv bytes] IV itself
3555            //    [byte] master key length = Nmk
3556            //    [array of Nmk bytes] master key itself
3557            //    [byte] MK checksum hash length = Nck
3558            //    [array of Nck bytes] master key checksum hash
3559            //
3560            // The checksum is the (master key + checksum salt), run through the
3561            // stated number of PBKDF2 rounds
3562            IV = c.getIV();
3563            byte[] mk = masterKeySpec.getEncoded();
3564            byte[] checksum = makeKeyChecksum(PBKDF_CURRENT, masterKeySpec.getEncoded(),
3565                    checksumSalt, PBKDF2_HASH_ROUNDS);
3566
3567            ByteArrayOutputStream blob = new ByteArrayOutputStream(IV.length + mk.length
3568                    + checksum.length + 3);
3569            DataOutputStream mkOut = new DataOutputStream(blob);
3570            mkOut.writeByte(IV.length);
3571            mkOut.write(IV);
3572            mkOut.writeByte(mk.length);
3573            mkOut.write(mk);
3574            mkOut.writeByte(checksum.length);
3575            mkOut.write(checksum);
3576            mkOut.flush();
3577            byte[] encryptedMk = mkC.doFinal(blob.toByteArray());
3578            headerbuf.append(byteArrayToHex(encryptedMk));
3579            headerbuf.append('\n');
3580
3581            return finalOutput;
3582        }
3583
3584        private void finalizeBackup(OutputStream out) {
3585            try {
3586                // A standard 'tar' EOF sequence: two 512-byte blocks of all zeroes.
3587                byte[] eof = new byte[512 * 2]; // newly allocated == zero filled
3588                out.write(eof);
3589            } catch (IOException e) {
3590                Slog.w(TAG, "Error attempting to finalize backup stream");
3591            }
3592        }
3593
3594        @Override
3595        public void run() {
3596            Slog.i(TAG, "--- Performing full-dataset adb backup ---");
3597
3598            TreeMap<String, PackageInfo> packagesToBackup = new TreeMap<String, PackageInfo>();
3599            FullBackupObbConnection obbConnection = new FullBackupObbConnection();
3600            obbConnection.establish();  // we'll want this later
3601
3602            sendStartBackup();
3603
3604            // doAllApps supersedes the package set if any
3605            if (mAllApps) {
3606                List<PackageInfo> allPackages = mPackageManager.getInstalledPackages(
3607                        PackageManager.GET_SIGNATURES);
3608                for (int i = 0; i < allPackages.size(); i++) {
3609                    PackageInfo pkg = allPackages.get(i);
3610                    // Exclude system apps if we've been asked to do so
3611                    if (mIncludeSystem == true
3612                            || ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0)) {
3613                        packagesToBackup.put(pkg.packageName, pkg);
3614                    }
3615                }
3616            }
3617
3618            // If we're doing widget state as well, ensure that we have all the involved
3619            // host & provider packages in the set
3620            if (mDoWidgets) {
3621                List<String> pkgs =
3622                        AppWidgetBackupBridge.getWidgetParticipants(UserHandle.USER_OWNER);
3623                if (pkgs != null) {
3624                    if (MORE_DEBUG) {
3625                        Slog.i(TAG, "Adding widget participants to backup set:");
3626                        StringBuilder sb = new StringBuilder(128);
3627                        sb.append("   ");
3628                        for (String s : pkgs) {
3629                            sb.append(' ');
3630                            sb.append(s);
3631                        }
3632                        Slog.i(TAG, sb.toString());
3633                    }
3634                    addPackagesToSet(packagesToBackup, pkgs);
3635                }
3636            }
3637
3638            // Now process the command line argument packages, if any. Note that explicitly-
3639            // named system-partition packages will be included even if includeSystem was
3640            // set to false.
3641            if (mPackages != null) {
3642                addPackagesToSet(packagesToBackup, mPackages);
3643            }
3644
3645            // Now we cull any inapplicable / inappropriate packages from the set.  This
3646            // includes the special shared-storage agent package; we handle that one
3647            // explicitly at the end of the backup pass.
3648            Iterator<Entry<String, PackageInfo>> iter = packagesToBackup.entrySet().iterator();
3649            while (iter.hasNext()) {
3650                PackageInfo pkg = iter.next().getValue();
3651                if (!appIsEligibleForBackup(pkg.applicationInfo)) {
3652                    iter.remove();
3653                }
3654            }
3655
3656            // flatten the set of packages now so we can explicitly control the ordering
3657            ArrayList<PackageInfo> backupQueue =
3658                    new ArrayList<PackageInfo>(packagesToBackup.values());
3659            FileOutputStream ofstream = new FileOutputStream(mOutputFile.getFileDescriptor());
3660            OutputStream out = null;
3661
3662            PackageInfo pkg = null;
3663            try {
3664                boolean encrypting = (mEncryptPassword != null && mEncryptPassword.length() > 0);
3665
3666                // Only allow encrypted backups of encrypted devices
3667                if (deviceIsEncrypted() && !encrypting) {
3668                    Slog.e(TAG, "Unencrypted backup of encrypted device; aborting");
3669                    return;
3670                }
3671
3672                OutputStream finalOutput = ofstream;
3673
3674                // Verify that the given password matches the currently-active
3675                // backup password, if any
3676                if (!backupPasswordMatches(mCurrentPassword)) {
3677                    if (DEBUG) Slog.w(TAG, "Backup password mismatch; aborting");
3678                    return;
3679                }
3680
3681                // Write the global file header.  All strings are UTF-8 encoded; lines end
3682                // with a '\n' byte.  Actual backup data begins immediately following the
3683                // final '\n'.
3684                //
3685                // line 1: "ANDROID BACKUP"
3686                // line 2: backup file format version, currently "2"
3687                // line 3: compressed?  "0" if not compressed, "1" if compressed.
3688                // line 4: name of encryption algorithm [currently only "none" or "AES-256"]
3689                //
3690                // When line 4 is not "none", then additional header data follows:
3691                //
3692                // line 5: user password salt [hex]
3693                // line 6: master key checksum salt [hex]
3694                // line 7: number of PBKDF2 rounds to use (same for user & master) [decimal]
3695                // line 8: IV of the user key [hex]
3696                // line 9: master key blob [hex]
3697                //     IV of the master key, master key itself, master key checksum hash
3698                //
3699                // The master key checksum is the master key plus its checksum salt, run through
3700                // 10k rounds of PBKDF2.  This is used to verify that the user has supplied the
3701                // correct password for decrypting the archive:  the master key decrypted from
3702                // the archive using the user-supplied password is also run through PBKDF2 in
3703                // this way, and if the result does not match the checksum as stored in the
3704                // archive, then we know that the user-supplied password does not match the
3705                // archive's.
3706                StringBuilder headerbuf = new StringBuilder(1024);
3707
3708                headerbuf.append(BACKUP_FILE_HEADER_MAGIC);
3709                headerbuf.append(BACKUP_FILE_VERSION); // integer, no trailing \n
3710                headerbuf.append(mCompress ? "\n1\n" : "\n0\n");
3711
3712                try {
3713                    // Set up the encryption stage if appropriate, and emit the correct header
3714                    if (encrypting) {
3715                        finalOutput = emitAesBackupHeader(headerbuf, finalOutput);
3716                    } else {
3717                        headerbuf.append("none\n");
3718                    }
3719
3720                    byte[] header = headerbuf.toString().getBytes("UTF-8");
3721                    ofstream.write(header);
3722
3723                    // Set up the compression stage feeding into the encryption stage (if any)
3724                    if (mCompress) {
3725                        Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION);
3726                        finalOutput = new DeflaterOutputStream(finalOutput, deflater, true);
3727                    }
3728
3729                    out = finalOutput;
3730                } catch (Exception e) {
3731                    // Should never happen!
3732                    Slog.e(TAG, "Unable to emit archive header", e);
3733                    return;
3734                }
3735
3736                // Shared storage if requested
3737                if (mIncludeShared) {
3738                    try {
3739                        pkg = mPackageManager.getPackageInfo(SHARED_BACKUP_AGENT_PACKAGE, 0);
3740                        backupQueue.add(pkg);
3741                    } catch (NameNotFoundException e) {
3742                        Slog.e(TAG, "Unable to find shared-storage backup handler");
3743                    }
3744                }
3745
3746                // Now actually run the constructed backup sequence
3747                int N = backupQueue.size();
3748                for (int i = 0; i < N; i++) {
3749                    pkg = backupQueue.get(i);
3750                    final boolean isSharedStorage =
3751                            pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE);
3752
3753                    mBackupEngine = new FullBackupEngine(out, pkg.packageName, mIncludeApks);
3754                    sendOnBackupPackage(isSharedStorage ? "Shared storage" : pkg.packageName);
3755                    mBackupEngine.backupOnePackage(pkg);
3756
3757                    // after the app's agent runs to handle its private filesystem
3758                    // contents, back up any OBB content it has on its behalf.
3759                    if (mIncludeObbs) {
3760                        boolean obbOkay = obbConnection.backupObbs(pkg, out);
3761                        if (!obbOkay) {
3762                            throw new RuntimeException("Failure writing OBB stack for " + pkg);
3763                        }
3764                    }
3765                }
3766
3767                // Done!
3768                finalizeBackup(out);
3769            } catch (RemoteException e) {
3770                Slog.e(TAG, "App died during full backup");
3771            } catch (Exception e) {
3772                Slog.e(TAG, "Internal exception during full backup", e);
3773            } finally {
3774                try {
3775                    if (out != null) out.close();
3776                    mOutputFile.close();
3777                } catch (IOException e) {
3778                    /* nothing we can do about this */
3779                }
3780                synchronized (mCurrentOpLock) {
3781                    mCurrentOperations.clear();
3782                }
3783                synchronized (mLatch) {
3784                    mLatch.set(true);
3785                    mLatch.notifyAll();
3786                }
3787                sendEndBackup();
3788                obbConnection.tearDown();
3789                if (DEBUG) Slog.d(TAG, "Full backup pass complete.");
3790                mWakelock.release();
3791            }
3792        }
3793    }
3794
3795    // Full backup task extension used for transport-oriented operation
3796    class PerformFullTransportBackupTask extends FullBackupTask {
3797        static final String TAG = "PFTBT";
3798        ArrayList<PackageInfo> mPackages;
3799        boolean mUpdateSchedule;
3800        AtomicBoolean mLatch;
3801        AtomicBoolean mKeepRunning;     // signal from job scheduler
3802        FullBackupJob mJob;             // if a scheduled job needs to be finished afterwards
3803
3804        PerformFullTransportBackupTask(IFullBackupRestoreObserver observer,
3805                String[] whichPackages, boolean updateSchedule,
3806                FullBackupJob runningJob, AtomicBoolean latch) {
3807            super(observer);
3808            mUpdateSchedule = updateSchedule;
3809            mLatch = latch;
3810            mKeepRunning = new AtomicBoolean(true);
3811            mJob = runningJob;
3812            mPackages = new ArrayList<PackageInfo>(whichPackages.length);
3813
3814            for (String pkg : whichPackages) {
3815                try {
3816                    PackageInfo info = mPackageManager.getPackageInfo(pkg,
3817                            PackageManager.GET_SIGNATURES);
3818                    if ((info.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0
3819                            || pkg.equals(SHARED_BACKUP_AGENT_PACKAGE)) {
3820                        // Cull any packages that have indicated that backups are not permitted,
3821                        // as well as any explicit mention of the 'special' shared-storage agent
3822                        // package (we handle that one at the end).
3823                        if (MORE_DEBUG) {
3824                            Slog.d(TAG, "Ignoring opted-out package " + pkg);
3825                        }
3826                        continue;
3827                    } else if ((info.applicationInfo.uid < Process.FIRST_APPLICATION_UID)
3828                            && (info.applicationInfo.backupAgentName == null)) {
3829                        // Cull any packages that run as system-domain uids but do not define their
3830                        // own backup agents
3831                        if (MORE_DEBUG) {
3832                            Slog.d(TAG, "Ignoring non-agent system package " + pkg);
3833                        }
3834                        continue;
3835                    }
3836                    mPackages.add(info);
3837                } catch (NameNotFoundException e) {
3838                    Slog.i(TAG, "Requested package " + pkg + " not found; ignoring");
3839                }
3840            }
3841        }
3842
3843        public void setRunning(boolean running) {
3844            mKeepRunning.set(running);
3845        }
3846
3847        @Override
3848        public void run() {
3849            // data from the app, passed to us for bridging to the transport
3850            ParcelFileDescriptor[] enginePipes = null;
3851
3852            // Pipe through which we write data to the transport
3853            ParcelFileDescriptor[] transportPipes = null;
3854
3855            PackageInfo currentPackage;
3856
3857            try {
3858                if (!mEnabled || !mProvisioned) {
3859                    // Backups are globally disabled, so don't proceed.
3860                    if (DEBUG) {
3861                        Slog.i(TAG, "full backup requested but e=" + mEnabled
3862                                + " p=" + mProvisioned + "; ignoring");
3863                    }
3864                    mUpdateSchedule = false;
3865                    return;
3866                }
3867
3868                IBackupTransport transport = getTransport(mCurrentTransport);
3869                if (transport == null) {
3870                    Slog.w(TAG, "Transport not present; full data backup not performed");
3871                    return;
3872                }
3873
3874                // Set up to send data to the transport
3875                final int N = mPackages.size();
3876                for (int i = 0; i < N; i++) {
3877                    currentPackage = mPackages.get(i);
3878                    if (DEBUG) {
3879                        Slog.i(TAG, "Initiating full-data transport backup of "
3880                                + currentPackage.packageName);
3881                    }
3882                    EventLog.writeEvent(EventLogTags.FULL_BACKUP_PACKAGE,
3883                            currentPackage.packageName);
3884
3885                    transportPipes = ParcelFileDescriptor.createPipe();
3886
3887                    // Tell the transport the data's coming
3888                    int result = transport.performFullBackup(currentPackage,
3889                            transportPipes[0]);
3890                    if (result == BackupTransport.TRANSPORT_OK) {
3891                        // The transport has its own copy of the read end of the pipe,
3892                        // so close ours now
3893                        transportPipes[0].close();
3894                        transportPipes[0] = null;
3895
3896                        // Now set up the backup engine / data source end of things
3897                        enginePipes = ParcelFileDescriptor.createPipe();
3898                        AtomicBoolean runnerLatch = new AtomicBoolean(false);
3899                        SinglePackageBackupRunner backupRunner =
3900                                new SinglePackageBackupRunner(enginePipes[1], currentPackage,
3901                                        runnerLatch);
3902                        // The runner dup'd the pipe half, so we close it here
3903                        enginePipes[1].close();
3904                        enginePipes[1] = null;
3905
3906                        // Spin off the runner to fetch the app's data and pipe it
3907                        // into the engine pipes
3908                        (new Thread(backupRunner, "package-backup-bridge")).start();
3909
3910                        // Read data off the engine pipe and pass it to the transport
3911                        // pipe until we hit EOD on the input stream.
3912                        FileInputStream in = new FileInputStream(
3913                                enginePipes[0].getFileDescriptor());
3914                        FileOutputStream out = new FileOutputStream(
3915                                transportPipes[1].getFileDescriptor());
3916                        byte[] buffer = new byte[8192];
3917                        int nRead = 0;
3918                        do {
3919                            if (!mKeepRunning.get()) {
3920                                if (DEBUG_SCHEDULING) {
3921                                    Slog.i(TAG, "Full backup task told to stop");
3922                                }
3923                                break;
3924                            }
3925                            nRead = in.read(buffer);
3926                            if (nRead > 0) {
3927                                out.write(buffer, 0, nRead);
3928                                result = transport.sendBackupData(nRead);
3929                            }
3930                        } while (nRead > 0 && result == BackupTransport.TRANSPORT_OK);
3931
3932                        // If we've lost our running criteria, tell the transport to cancel
3933                        // and roll back this (partial) backup payload; otherwise tell it
3934                        // that we've reached the clean finish state.
3935                        if (!mKeepRunning.get()) {
3936                            result = BackupTransport.TRANSPORT_ERROR;
3937                            transport.cancelFullBackup();
3938                        } else {
3939                            // If we were otherwise in a good state, now interpret the final
3940                            // result based on what finishBackup() returns.  If we're in a
3941                            // failure case already, preserve that result and ignore whatever
3942                            // finishBackup() reports.
3943                            final int finishResult = transport.finishBackup();
3944                            if (result == BackupTransport.TRANSPORT_OK) {
3945                                result = finishResult;
3946                            }
3947                        }
3948
3949                        if (MORE_DEBUG) {
3950                            Slog.i(TAG, "Done trying to send backup data: result=" + result);
3951                        }
3952
3953                        if (result != BackupTransport.TRANSPORT_OK) {
3954                            Slog.e(TAG, "Error " + result
3955                                    + " backing up " + currentPackage.packageName);
3956                        }
3957                    }
3958
3959                    // Roll this package to the end of the backup queue if we're
3960                    // in a queue-driven mode (regardless of success/failure)
3961                    if (mUpdateSchedule) {
3962                        enqueueFullBackup(currentPackage.packageName,
3963                                System.currentTimeMillis());
3964                    }
3965
3966                    if (result == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
3967                        if (DEBUG) {
3968                            Slog.i(TAG, "Transport rejected backup of "
3969                                    + currentPackage.packageName
3970                                    + ", skipping");
3971                        }
3972                        EventLog.writeEvent(EventLogTags.FULL_BACKUP_AGENT_FAILURE,
3973                                currentPackage.packageName, "transport rejected");
3974                        // do nothing, clean up, and continue looping
3975                    } else if (result != BackupTransport.TRANSPORT_OK) {
3976                        if (DEBUG) {
3977                            Slog.i(TAG, "Transport failed; aborting backup: " + result);
3978                            EventLog.writeEvent(EventLogTags.FULL_BACKUP_TRANSPORT_FAILURE);
3979                            return;
3980                        }
3981                    } else {
3982                        // Success!
3983                        EventLog.writeEvent(EventLogTags.FULL_BACKUP_SUCCESS,
3984                                currentPackage.packageName);
3985                        logBackupComplete(currentPackage.packageName);
3986                    }
3987                    cleanUpPipes(transportPipes);
3988                    cleanUpPipes(enginePipes);
3989                    currentPackage = null;
3990                }
3991
3992                if (DEBUG) {
3993                    Slog.i(TAG, "Full backup completed.");
3994                }
3995            } catch (Exception e) {
3996                Slog.w(TAG, "Exception trying full transport backup", e);
3997            } finally {
3998                cleanUpPipes(transportPipes);
3999                cleanUpPipes(enginePipes);
4000
4001                if (mJob != null) {
4002                    mJob.finishBackupPass();
4003                }
4004
4005                synchronized (mQueueLock) {
4006                    mRunningFullBackupTask = null;
4007                }
4008
4009                synchronized (mLatch) {
4010                    mLatch.set(true);
4011                    mLatch.notifyAll();
4012                }
4013
4014                // Now that we're actually done with schedule-driven work, reschedule
4015                // the next pass based on the new queue state.
4016                if (mUpdateSchedule) {
4017                    scheduleNextFullBackupJob();
4018                }
4019            }
4020        }
4021
4022        void cleanUpPipes(ParcelFileDescriptor[] pipes) {
4023            if (pipes != null) {
4024                if (pipes[0] != null) {
4025                    ParcelFileDescriptor fd = pipes[0];
4026                    pipes[0] = null;
4027                    try {
4028                        fd.close();
4029                    } catch (IOException e) {
4030                        Slog.w(TAG, "Unable to close pipe!");
4031                    }
4032                }
4033                if (pipes[1] != null) {
4034                    ParcelFileDescriptor fd = pipes[1];
4035                    pipes[1] = null;
4036                    try {
4037                        fd.close();
4038                    } catch (IOException e) {
4039                        Slog.w(TAG, "Unable to close pipe!");
4040                    }
4041                }
4042            }
4043        }
4044
4045        // Run the backup and pipe it back to the given socket -- expects to run on
4046        // a standalone thread.  The  runner owns this half of the pipe, and closes
4047        // it to indicate EOD to the other end.
4048        class SinglePackageBackupRunner implements Runnable {
4049            final ParcelFileDescriptor mOutput;
4050            final PackageInfo mTarget;
4051            final AtomicBoolean mLatch;
4052
4053            SinglePackageBackupRunner(ParcelFileDescriptor output, PackageInfo target,
4054                    AtomicBoolean latch) throws IOException {
4055                int oldfd = output.getFd();
4056                mOutput = ParcelFileDescriptor.dup(output.getFileDescriptor());
4057                mTarget = target;
4058                mLatch = latch;
4059            }
4060
4061            @Override
4062            public void run() {
4063                try {
4064                    FileOutputStream out = new FileOutputStream(mOutput.getFileDescriptor());
4065                    FullBackupEngine engine = new FullBackupEngine(out, mTarget.packageName, false);
4066                    engine.backupOnePackage(mTarget);
4067                } catch (Exception e) {
4068                    Slog.e(TAG, "Exception during full package backup of " + mTarget);
4069                } finally {
4070                    synchronized (mLatch) {
4071                        mLatch.set(true);
4072                        mLatch.notifyAll();
4073                    }
4074                    try {
4075                        mOutput.close();
4076                    } catch (IOException e) {
4077                        Slog.w(TAG, "Error closing transport pipe in runner");
4078                    }
4079                }
4080            }
4081
4082        }
4083    }
4084
4085    // ----- Full-data backup scheduling -----
4086
4087    /**
4088     * Schedule a job to tell us when it's a good time to run a full backup
4089     */
4090    void scheduleNextFullBackupJob() {
4091        synchronized (mQueueLock) {
4092            if (mFullBackupQueue.size() > 0) {
4093                // schedule the next job at the point in the future when the least-recently
4094                // backed up app comes due for backup again; or immediately if it's already
4095                // due.
4096                long upcomingLastBackup = mFullBackupQueue.get(0).lastBackup;
4097                long timeSinceLast = System.currentTimeMillis() - upcomingLastBackup;
4098                final long latency = (timeSinceLast < MIN_FULL_BACKUP_INTERVAL)
4099                        ? (MIN_FULL_BACKUP_INTERVAL - timeSinceLast) : 0;
4100                Runnable r = new Runnable() {
4101                    @Override public void run() {
4102                        FullBackupJob.schedule(mContext, latency);
4103                    }
4104                };
4105                mBackupHandler.postDelayed(r, 2500);
4106            } else {
4107                if (DEBUG_SCHEDULING) {
4108                    Slog.i(TAG, "Full backup queue empty; not scheduling");
4109                }
4110            }
4111        }
4112    }
4113
4114    /**
4115     * Enqueue full backup for the given app, with a note about when it last ran.
4116     */
4117    void enqueueFullBackup(String packageName, long lastBackedUp) {
4118        FullBackupEntry newEntry = new FullBackupEntry(packageName, lastBackedUp);
4119        synchronized (mQueueLock) {
4120            int N = mFullBackupQueue.size();
4121            // First, sanity check that we aren't adding a duplicate.  Slow but
4122            // straightforward; we'll have at most on the order of a few hundred
4123            // items in this list.
4124            for (int i = N-1; i >= 0; i--) {
4125                final FullBackupEntry e = mFullBackupQueue.get(i);
4126                if (packageName.equals(e.packageName)) {
4127                    if (DEBUG) {
4128                        Slog.w(TAG, "Removing schedule queue dupe of " + packageName);
4129                    }
4130                    mFullBackupQueue.remove(i);
4131                }
4132            }
4133
4134            // This is also slow but easy for modest numbers of apps: work backwards
4135            // from the end of the queue until we find an item whose last backup
4136            // time was before this one, then insert this new entry after it.
4137            int which;
4138            for (which = mFullBackupQueue.size() - 1; which >= 0; which--) {
4139                final FullBackupEntry entry = mFullBackupQueue.get(which);
4140                if (entry.lastBackup <= lastBackedUp) {
4141                    mFullBackupQueue.add(which + 1, newEntry);
4142                    break;
4143                }
4144            }
4145            if (which < 0) {
4146                // this one is earlier than any existing one, so prepend
4147                mFullBackupQueue.add(0, newEntry);
4148            }
4149        }
4150        writeFullBackupScheduleAsync();
4151    }
4152
4153    /**
4154     * Conditions are right for a full backup operation, so run one.  The model we use is
4155     * to perform one app backup per scheduled job execution, and to reschedule the job
4156     * with zero latency as long as conditions remain right and we still have work to do.
4157     *
4158     * @return Whether ongoing work will continue.  The return value here will be passed
4159     *         along as the return value to the scheduled job's onStartJob() callback.
4160     */
4161    boolean beginFullBackup(FullBackupJob scheduledJob) {
4162        long now = System.currentTimeMillis();
4163        FullBackupEntry entry = null;
4164
4165        if (!mEnabled || !mProvisioned) {
4166            // Backups are globally disabled, so don't proceed.  We also don't reschedule
4167            // the job driving automatic backups; that job will be scheduled again when
4168            // the user enables backup.
4169            if (MORE_DEBUG) {
4170                Slog.i(TAG, "beginFullBackup but e=" + mEnabled
4171                        + " p=" + mProvisioned + "; ignoring");
4172            }
4173            return false;
4174        }
4175
4176        if (DEBUG_SCHEDULING) {
4177            Slog.i(TAG, "Beginning scheduled full backup operation");
4178        }
4179
4180        // Great; we're able to run full backup jobs now.  See if we have any work to do.
4181        synchronized (mQueueLock) {
4182            if (mRunningFullBackupTask != null) {
4183                Slog.e(TAG, "Backup triggered but one already/still running!");
4184                return false;
4185            }
4186
4187            if (mFullBackupQueue.size() == 0) {
4188                // no work to do so just bow out
4189                if (DEBUG) {
4190                    Slog.i(TAG, "Backup queue empty; doing nothing");
4191                }
4192                return false;
4193            }
4194
4195            entry = mFullBackupQueue.get(0);
4196            long timeSinceRun = now - entry.lastBackup;
4197            if (timeSinceRun < MIN_FULL_BACKUP_INTERVAL) {
4198                // It's too early to back up the next thing in the queue, so bow out
4199                if (MORE_DEBUG) {
4200                    Slog.i(TAG, "Device ready but too early to back up next app");
4201                }
4202                final long latency = MIN_FULL_BACKUP_INTERVAL - timeSinceRun;
4203                mBackupHandler.post(new Runnable() {
4204                    @Override public void run() {
4205                        FullBackupJob.schedule(mContext, latency);
4206                    }
4207                });
4208                return false;
4209            }
4210
4211            // Okay, the top thing is runnable now.  Pop it off and get going.
4212            mFullBackupQueue.remove(0);
4213            AtomicBoolean latch = new AtomicBoolean(false);
4214            String[] pkg = new String[] {entry.packageName};
4215            mRunningFullBackupTask = new PerformFullTransportBackupTask(null, pkg, true,
4216                    scheduledJob, latch);
4217            (new Thread(mRunningFullBackupTask)).start();
4218        }
4219
4220        return true;
4221    }
4222
4223    // The job scheduler says our constraints don't hold any more,
4224    // so tear down any ongoing backup task right away.
4225    void endFullBackup() {
4226        synchronized (mQueueLock) {
4227            if (mRunningFullBackupTask != null) {
4228                if (DEBUG_SCHEDULING) {
4229                    Slog.i(TAG, "Telling running backup to stop");
4230                }
4231                mRunningFullBackupTask.setRunning(false);
4232            }
4233        }
4234    }
4235
4236    // ----- Restore infrastructure -----
4237
4238    abstract class RestoreEngine {
4239        static final String TAG = "RestoreEngine";
4240
4241        public static final int SUCCESS = 0;
4242        public static final int TARGET_FAILURE = -2;
4243        public static final int TRANSPORT_FAILURE = -3;
4244
4245        private AtomicBoolean mRunning = new AtomicBoolean(false);
4246        private AtomicInteger mResult = new AtomicInteger(SUCCESS);
4247
4248        public boolean isRunning() {
4249            return mRunning.get();
4250        }
4251
4252        public void setRunning(boolean stillRunning) {
4253            synchronized (mRunning) {
4254                mRunning.set(stillRunning);
4255                mRunning.notifyAll();
4256            }
4257        }
4258
4259        public int waitForResult() {
4260            synchronized (mRunning) {
4261                while (isRunning()) {
4262                    try {
4263                        mRunning.wait();
4264                    } catch (InterruptedException e) {}
4265                }
4266            }
4267            return getResult();
4268        }
4269
4270        public int getResult() {
4271            return mResult.get();
4272        }
4273
4274        public void setResult(int result) {
4275            mResult.set(result);
4276        }
4277
4278        // TODO: abstract restore state and APIs
4279    }
4280
4281    // ----- Full restore from a file/socket -----
4282
4283    // Description of a file in the restore datastream
4284    static class FileMetadata {
4285        String packageName;             // name of the owning app
4286        String installerPackageName;    // name of the market-type app that installed the owner
4287        int type;                       // e.g. BackupAgent.TYPE_DIRECTORY
4288        String domain;                  // e.g. FullBackup.DATABASE_TREE_TOKEN
4289        String path;                    // subpath within the semantic domain
4290        long mode;                      // e.g. 0666 (actually int)
4291        long mtime;                     // last mod time, UTC time_t (actually int)
4292        long size;                      // bytes of content
4293
4294        @Override
4295        public String toString() {
4296            StringBuilder sb = new StringBuilder(128);
4297            sb.append("FileMetadata{");
4298            sb.append(packageName); sb.append(',');
4299            sb.append(type); sb.append(',');
4300            sb.append(domain); sb.append(':'); sb.append(path); sb.append(',');
4301            sb.append(size);
4302            sb.append('}');
4303            return sb.toString();
4304        }
4305    }
4306
4307    enum RestorePolicy {
4308        IGNORE,
4309        ACCEPT,
4310        ACCEPT_IF_APK
4311    }
4312
4313    // Full restore engine, used by both adb restore and transport-based full restore
4314    class FullRestoreEngine extends RestoreEngine {
4315        // Dedicated observer, if any
4316        IFullBackupRestoreObserver mObserver;
4317
4318        // Where we're delivering the file data as we go
4319        IBackupAgent mAgent;
4320
4321        // Are we permitted to only deliver a specific package's metadata?
4322        PackageInfo mOnlyPackage;
4323
4324        boolean mAllowApks;
4325        boolean mAllowObbs;
4326
4327        // Which package are we currently handling data for?
4328        String mAgentPackage;
4329
4330        // Info for working with the target app process
4331        ApplicationInfo mTargetApp;
4332
4333        // Machinery for restoring OBBs
4334        FullBackupObbConnection mObbConnection = null;
4335
4336        // possible handling states for a given package in the restore dataset
4337        final HashMap<String, RestorePolicy> mPackagePolicies
4338                = new HashMap<String, RestorePolicy>();
4339
4340        // installer package names for each encountered app, derived from the manifests
4341        final HashMap<String, String> mPackageInstallers = new HashMap<String, String>();
4342
4343        // Signatures for a given package found in its manifest file
4344        final HashMap<String, Signature[]> mManifestSignatures
4345                = new HashMap<String, Signature[]>();
4346
4347        // Packages we've already wiped data on when restoring their first file
4348        final HashSet<String> mClearedPackages = new HashSet<String>();
4349
4350        // How much data have we moved?
4351        long mBytes;
4352
4353        // Working buffer
4354        byte[] mBuffer;
4355
4356        // Pipes for moving data
4357        ParcelFileDescriptor[] mPipes = null;
4358
4359        // Widget blob to be restored out-of-band
4360        byte[] mWidgetData = null;
4361
4362        // Runner that can be placed in a separate thread to do in-process
4363        // invocations of the full restore API asynchronously
4364        class RestoreFileRunnable implements Runnable {
4365            IBackupAgent mAgent;
4366            FileMetadata mInfo;
4367            ParcelFileDescriptor mSocket;
4368            int mToken;
4369
4370            RestoreFileRunnable(IBackupAgent agent, FileMetadata info,
4371                    ParcelFileDescriptor socket, int token) throws IOException {
4372                mAgent = agent;
4373                mInfo = info;
4374                mToken = token;
4375
4376                // This class is used strictly for process-local binder invocations.  The
4377                // semantics of ParcelFileDescriptor differ in this case; in particular, we
4378                // do not automatically get a 'dup'ed descriptor that we can can continue
4379                // to use asynchronously from the caller.  So, we make sure to dup it ourselves
4380                // before proceeding to do the restore.
4381                mSocket = ParcelFileDescriptor.dup(socket.getFileDescriptor());
4382            }
4383
4384            @Override
4385            public void run() {
4386                try {
4387                    mAgent.doRestoreFile(mSocket, mInfo.size, mInfo.type,
4388                            mInfo.domain, mInfo.path, mInfo.mode, mInfo.mtime,
4389                            mToken, mBackupManagerBinder);
4390                } catch (RemoteException e) {
4391                    // never happens; this is used strictly for local binder calls
4392                }
4393            }
4394        }
4395
4396        public FullRestoreEngine(IFullBackupRestoreObserver observer, PackageInfo onlyPackage,
4397                boolean allowApks, boolean allowObbs) {
4398            mObserver = observer;
4399            mOnlyPackage = onlyPackage;
4400            mAllowApks = allowApks;
4401            mAllowObbs = allowObbs;
4402            mBuffer = new byte[32 * 1024];
4403            mBytes = 0;
4404        }
4405
4406        public boolean restoreOneFile(InputStream instream) {
4407            if (!isRunning()) {
4408                Slog.w(TAG, "Restore engine used after halting");
4409                return false;
4410            }
4411
4412            FileMetadata info;
4413            try {
4414                if (MORE_DEBUG) {
4415                    Slog.v(TAG, "Reading tar header for restoring file");
4416                }
4417                info = readTarHeaders(instream);
4418                if (info != null) {
4419                    if (MORE_DEBUG) {
4420                        dumpFileMetadata(info);
4421                    }
4422
4423                    final String pkg = info.packageName;
4424                    if (!pkg.equals(mAgentPackage)) {
4425                        // In the single-package case, it's a semantic error to expect
4426                        // one app's data but see a different app's on the wire
4427                        if (mOnlyPackage != null) {
4428                            if (!pkg.equals(mOnlyPackage.packageName)) {
4429                                Slog.w(TAG, "Expected data for " + mOnlyPackage
4430                                        + " but saw " + pkg);
4431                                setResult(RestoreEngine.TRANSPORT_FAILURE);
4432                                setRunning(false);
4433                                return false;
4434                            }
4435                        }
4436
4437                        // okay, change in package; set up our various
4438                        // bookkeeping if we haven't seen it yet
4439                        if (!mPackagePolicies.containsKey(pkg)) {
4440                            mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
4441                        }
4442
4443                        // Clean up the previous agent relationship if necessary,
4444                        // and let the observer know we're considering a new app.
4445                        if (mAgent != null) {
4446                            if (DEBUG) Slog.d(TAG, "Saw new package; finalizing old one");
4447                            // Now we're really done
4448                            tearDownPipes();
4449                            tearDownAgent(mTargetApp);
4450                            mTargetApp = null;
4451                            mAgentPackage = null;
4452                        }
4453                    }
4454
4455                    if (info.path.equals(BACKUP_MANIFEST_FILENAME)) {
4456                        mPackagePolicies.put(pkg, readAppManifest(info, instream));
4457                        mPackageInstallers.put(pkg, info.installerPackageName);
4458                        // We've read only the manifest content itself at this point,
4459                        // so consume the footer before looping around to the next
4460                        // input file
4461                        skipTarPadding(info.size, instream);
4462                        sendOnRestorePackage(pkg);
4463                    } else if (info.path.equals(BACKUP_METADATA_FILENAME)) {
4464                        // Metadata blobs!
4465                        readMetadata(info, instream);
4466                        skipTarPadding(info.size, instream);
4467                    } else {
4468                        // Non-manifest, so it's actual file data.  Is this a package
4469                        // we're ignoring?
4470                        boolean okay = true;
4471                        RestorePolicy policy = mPackagePolicies.get(pkg);
4472                        switch (policy) {
4473                            case IGNORE:
4474                                okay = false;
4475                                break;
4476
4477                            case ACCEPT_IF_APK:
4478                                // If we're in accept-if-apk state, then the first file we
4479                                // see MUST be the apk.
4480                                if (info.domain.equals(FullBackup.APK_TREE_TOKEN)) {
4481                                    if (DEBUG) Slog.d(TAG, "APK file; installing");
4482                                    // Try to install the app.
4483                                    String installerName = mPackageInstallers.get(pkg);
4484                                    okay = installApk(info, installerName, instream);
4485                                    // good to go; promote to ACCEPT
4486                                    mPackagePolicies.put(pkg, (okay)
4487                                            ? RestorePolicy.ACCEPT
4488                                                    : RestorePolicy.IGNORE);
4489                                    // At this point we've consumed this file entry
4490                                    // ourselves, so just strip the tar footer and
4491                                    // go on to the next file in the input stream
4492                                    skipTarPadding(info.size, instream);
4493                                    return true;
4494                                } else {
4495                                    // File data before (or without) the apk.  We can't
4496                                    // handle it coherently in this case so ignore it.
4497                                    mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
4498                                    okay = false;
4499                                }
4500                                break;
4501
4502                            case ACCEPT:
4503                                if (info.domain.equals(FullBackup.APK_TREE_TOKEN)) {
4504                                    if (DEBUG) Slog.d(TAG, "apk present but ACCEPT");
4505                                    // we can take the data without the apk, so we
4506                                    // *want* to do so.  skip the apk by declaring this
4507                                    // one file not-okay without changing the restore
4508                                    // policy for the package.
4509                                    okay = false;
4510                                }
4511                                break;
4512
4513                            default:
4514                                // Something has gone dreadfully wrong when determining
4515                                // the restore policy from the manifest.  Ignore the
4516                                // rest of this package's data.
4517                                Slog.e(TAG, "Invalid policy from manifest");
4518                                okay = false;
4519                                mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
4520                                break;
4521                        }
4522
4523                        // Is it a *file* we need to drop?
4524                        if (!isRestorableFile(info)) {
4525                            okay = false;
4526                        }
4527
4528                        // If the policy is satisfied, go ahead and set up to pipe the
4529                        // data to the agent.
4530                        if (DEBUG && okay && mAgent != null) {
4531                            Slog.i(TAG, "Reusing existing agent instance");
4532                        }
4533                        if (okay && mAgent == null) {
4534                            if (DEBUG) Slog.d(TAG, "Need to launch agent for " + pkg);
4535
4536                            try {
4537                                mTargetApp = mPackageManager.getApplicationInfo(pkg, 0);
4538
4539                                // If we haven't sent any data to this app yet, we probably
4540                                // need to clear it first.  Check that.
4541                                if (!mClearedPackages.contains(pkg)) {
4542                                    // apps with their own backup agents are
4543                                    // responsible for coherently managing a full
4544                                    // restore.
4545                                    if (mTargetApp.backupAgentName == null) {
4546                                        if (DEBUG) Slog.d(TAG, "Clearing app data preparatory to full restore");
4547                                        clearApplicationDataSynchronous(pkg);
4548                                    } else {
4549                                        if (DEBUG) Slog.d(TAG, "backup agent ("
4550                                                + mTargetApp.backupAgentName + ") => no clear");
4551                                    }
4552                                    mClearedPackages.add(pkg);
4553                                } else {
4554                                    if (DEBUG) Slog.d(TAG, "We've initialized this app already; no clear required");
4555                                }
4556
4557                                // All set; now set up the IPC and launch the agent
4558                                setUpPipes();
4559                                mAgent = bindToAgentSynchronous(mTargetApp,
4560                                        IApplicationThread.BACKUP_MODE_RESTORE_FULL);
4561                                mAgentPackage = pkg;
4562                            } catch (IOException e) {
4563                                // fall through to error handling
4564                            } catch (NameNotFoundException e) {
4565                                // fall through to error handling
4566                            }
4567
4568                            if (mAgent == null) {
4569                                if (DEBUG) Slog.d(TAG, "Unable to create agent for " + pkg);
4570                                okay = false;
4571                                tearDownPipes();
4572                                mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
4573                            }
4574                        }
4575
4576                        // Sanity check: make sure we never give data to the wrong app.  This
4577                        // should never happen but a little paranoia here won't go amiss.
4578                        if (okay && !pkg.equals(mAgentPackage)) {
4579                            Slog.e(TAG, "Restoring data for " + pkg
4580                                    + " but agent is for " + mAgentPackage);
4581                            okay = false;
4582                        }
4583
4584                        // At this point we have an agent ready to handle the full
4585                        // restore data as well as a pipe for sending data to
4586                        // that agent.  Tell the agent to start reading from the
4587                        // pipe.
4588                        if (okay) {
4589                            boolean agentSuccess = true;
4590                            long toCopy = info.size;
4591                            final int token = generateToken();
4592                            try {
4593                                prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL, null);
4594                                if (info.domain.equals(FullBackup.OBB_TREE_TOKEN)) {
4595                                    if (DEBUG) Slog.d(TAG, "Restoring OBB file for " + pkg
4596                                            + " : " + info.path);
4597                                    mObbConnection.restoreObbFile(pkg, mPipes[0],
4598                                            info.size, info.type, info.path, info.mode,
4599                                            info.mtime, token, mBackupManagerBinder);
4600                                } else {
4601                                    if (DEBUG) Slog.d(TAG, "Invoking agent to restore file "
4602                                            + info.path);
4603                                    // fire up the app's agent listening on the socket.  If
4604                                    // the agent is running in the system process we can't
4605                                    // just invoke it asynchronously, so we provide a thread
4606                                    // for it here.
4607                                    if (mTargetApp.processName.equals("system")) {
4608                                        Slog.d(TAG, "system process agent - spinning a thread");
4609                                        RestoreFileRunnable runner = new RestoreFileRunnable(
4610                                                mAgent, info, mPipes[0], token);
4611                                        new Thread(runner, "restore-sys-runner").start();
4612                                    } else {
4613                                        mAgent.doRestoreFile(mPipes[0], info.size, info.type,
4614                                                info.domain, info.path, info.mode, info.mtime,
4615                                                token, mBackupManagerBinder);
4616                                    }
4617                                }
4618                            } catch (IOException e) {
4619                                // couldn't dup the socket for a process-local restore
4620                                Slog.d(TAG, "Couldn't establish restore");
4621                                agentSuccess = false;
4622                                okay = false;
4623                            } catch (RemoteException e) {
4624                                // whoops, remote entity went away.  We'll eat the content
4625                                // ourselves, then, and not copy it over.
4626                                Slog.e(TAG, "Agent crashed during full restore");
4627                                agentSuccess = false;
4628                                okay = false;
4629                            }
4630
4631                            // Copy over the data if the agent is still good
4632                            if (okay) {
4633                                if (MORE_DEBUG) {
4634                                    Slog.v(TAG, "  copying to restore agent: "
4635                                            + toCopy + " bytes");
4636                                }
4637                                boolean pipeOkay = true;
4638                                FileOutputStream pipe = new FileOutputStream(
4639                                        mPipes[1].getFileDescriptor());
4640                                while (toCopy > 0) {
4641                                    int toRead = (toCopy > mBuffer.length)
4642                                            ? mBuffer.length : (int)toCopy;
4643                                    int nRead = instream.read(mBuffer, 0, toRead);
4644                                    if (nRead >= 0) mBytes += nRead;
4645                                    if (nRead <= 0) break;
4646                                    toCopy -= nRead;
4647
4648                                    // send it to the output pipe as long as things
4649                                    // are still good
4650                                    if (pipeOkay) {
4651                                        try {
4652                                            pipe.write(mBuffer, 0, nRead);
4653                                        } catch (IOException e) {
4654                                            Slog.e(TAG, "Failed to write to restore pipe", e);
4655                                            pipeOkay = false;
4656                                        }
4657                                    }
4658                                }
4659
4660                                // done sending that file!  Now we just need to consume
4661                                // the delta from info.size to the end of block.
4662                                skipTarPadding(info.size, instream);
4663
4664                                // and now that we've sent it all, wait for the remote
4665                                // side to acknowledge receipt
4666                                agentSuccess = waitUntilOperationComplete(token);
4667                            }
4668
4669                            // okay, if the remote end failed at any point, deal with
4670                            // it by ignoring the rest of the restore on it
4671                            if (!agentSuccess) {
4672                                if (DEBUG) {
4673                                    Slog.i(TAG, "Agent failure; ending restore");
4674                                }
4675                                mBackupHandler.removeMessages(MSG_TIMEOUT);
4676                                tearDownPipes();
4677                                tearDownAgent(mTargetApp);
4678                                mAgent = null;
4679                                mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
4680
4681                                // If this was a single-package restore, we halt immediately
4682                                // with an agent error under these circumstances
4683                                if (mOnlyPackage != null) {
4684                                    setResult(RestoreEngine.TARGET_FAILURE);
4685                                    setRunning(false);
4686                                    return false;
4687                                }
4688                            }
4689                        }
4690
4691                        // Problems setting up the agent communication, an explicitly
4692                        // dropped file, or an already-ignored package: skip to the
4693                        // next stream entry by reading and discarding this file.
4694                        if (!okay) {
4695                            if (DEBUG) Slog.d(TAG, "[discarding file content]");
4696                            long bytesToConsume = (info.size + 511) & ~511;
4697                            while (bytesToConsume > 0) {
4698                                int toRead = (bytesToConsume > mBuffer.length)
4699                                        ? mBuffer.length : (int)bytesToConsume;
4700                                long nRead = instream.read(mBuffer, 0, toRead);
4701                                if (nRead >= 0) mBytes += nRead;
4702                                if (nRead <= 0) break;
4703                                bytesToConsume -= nRead;
4704                            }
4705                        }
4706                    }
4707                }
4708            } catch (IOException e) {
4709                if (DEBUG) Slog.w(TAG, "io exception on restore socket read", e);
4710                setResult(RestoreEngine.TRANSPORT_FAILURE);
4711                info = null;
4712            }
4713
4714            // If we got here we're either running smoothly or we've finished
4715            if (info == null) {
4716                if (MORE_DEBUG) {
4717                    Slog.i(TAG, "No [more] data for this package; tearing down");
4718                }
4719                tearDownPipes();
4720                tearDownAgent(mTargetApp);
4721                setRunning(false);
4722            }
4723            return (info != null);
4724        }
4725
4726        void setUpPipes() throws IOException {
4727            mPipes = ParcelFileDescriptor.createPipe();
4728        }
4729
4730        void tearDownPipes() {
4731            if (mPipes != null) {
4732                try {
4733                    mPipes[0].close();
4734                    mPipes[0] = null;
4735                    mPipes[1].close();
4736                    mPipes[1] = null;
4737                } catch (IOException e) {
4738                    Slog.w(TAG, "Couldn't close agent pipes", e);
4739                }
4740                mPipes = null;
4741            }
4742        }
4743
4744        void tearDownAgent(ApplicationInfo app) {
4745            if (mAgent != null) {
4746                try {
4747                    // unbind and tidy up even on timeout or failure, just in case
4748                    mActivityManager.unbindBackupAgent(app);
4749
4750                    // The agent was running with a stub Application object, so shut it down.
4751                    // !!! We hardcode the confirmation UI's package name here rather than use a
4752                    //     manifest flag!  TODO something less direct.
4753                    if (app.uid != Process.SYSTEM_UID
4754                            && !app.packageName.equals("com.android.backupconfirm")) {
4755                        if (DEBUG) Slog.d(TAG, "Killing host process");
4756                        mActivityManager.killApplicationProcess(app.processName, app.uid);
4757                    } else {
4758                        if (DEBUG) Slog.d(TAG, "Not killing after full restore");
4759                    }
4760                } catch (RemoteException e) {
4761                    Slog.d(TAG, "Lost app trying to shut down");
4762                }
4763                mAgent = null;
4764            }
4765        }
4766
4767        class RestoreInstallObserver extends IPackageInstallObserver.Stub {
4768            final AtomicBoolean mDone = new AtomicBoolean();
4769            String mPackageName;
4770            int mResult;
4771
4772            public void reset() {
4773                synchronized (mDone) {
4774                    mDone.set(false);
4775                }
4776            }
4777
4778            public void waitForCompletion() {
4779                synchronized (mDone) {
4780                    while (mDone.get() == false) {
4781                        try {
4782                            mDone.wait();
4783                        } catch (InterruptedException e) { }
4784                    }
4785                }
4786            }
4787
4788            int getResult() {
4789                return mResult;
4790            }
4791
4792            @Override
4793            public void packageInstalled(String packageName, int returnCode)
4794                    throws RemoteException {
4795                synchronized (mDone) {
4796                    mResult = returnCode;
4797                    mPackageName = packageName;
4798                    mDone.set(true);
4799                    mDone.notifyAll();
4800                }
4801            }
4802        }
4803
4804        class RestoreDeleteObserver extends IPackageDeleteObserver.Stub {
4805            final AtomicBoolean mDone = new AtomicBoolean();
4806            int mResult;
4807
4808            public void reset() {
4809                synchronized (mDone) {
4810                    mDone.set(false);
4811                }
4812            }
4813
4814            public void waitForCompletion() {
4815                synchronized (mDone) {
4816                    while (mDone.get() == false) {
4817                        try {
4818                            mDone.wait();
4819                        } catch (InterruptedException e) { }
4820                    }
4821                }
4822            }
4823
4824            @Override
4825            public void packageDeleted(String packageName, int returnCode) throws RemoteException {
4826                synchronized (mDone) {
4827                    mResult = returnCode;
4828                    mDone.set(true);
4829                    mDone.notifyAll();
4830                }
4831            }
4832        }
4833
4834        final RestoreInstallObserver mInstallObserver = new RestoreInstallObserver();
4835        final RestoreDeleteObserver mDeleteObserver = new RestoreDeleteObserver();
4836
4837        boolean installApk(FileMetadata info, String installerPackage, InputStream instream) {
4838            boolean okay = true;
4839
4840            if (DEBUG) Slog.d(TAG, "Installing from backup: " + info.packageName);
4841
4842            // The file content is an .apk file.  Copy it out to a staging location and
4843            // attempt to install it.
4844            File apkFile = new File(mDataDir, info.packageName);
4845            try {
4846                FileOutputStream apkStream = new FileOutputStream(apkFile);
4847                byte[] buffer = new byte[32 * 1024];
4848                long size = info.size;
4849                while (size > 0) {
4850                    long toRead = (buffer.length < size) ? buffer.length : size;
4851                    int didRead = instream.read(buffer, 0, (int)toRead);
4852                    if (didRead >= 0) mBytes += didRead;
4853                    apkStream.write(buffer, 0, didRead);
4854                    size -= didRead;
4855                }
4856                apkStream.close();
4857
4858                // make sure the installer can read it
4859                apkFile.setReadable(true, false);
4860
4861                // Now install it
4862                Uri packageUri = Uri.fromFile(apkFile);
4863                mInstallObserver.reset();
4864                mPackageManager.installPackage(packageUri, mInstallObserver,
4865                        PackageManager.INSTALL_REPLACE_EXISTING | PackageManager.INSTALL_FROM_ADB,
4866                        installerPackage);
4867                mInstallObserver.waitForCompletion();
4868
4869                if (mInstallObserver.getResult() != PackageManager.INSTALL_SUCCEEDED) {
4870                    // The only time we continue to accept install of data even if the
4871                    // apk install failed is if we had already determined that we could
4872                    // accept the data regardless.
4873                    if (mPackagePolicies.get(info.packageName) != RestorePolicy.ACCEPT) {
4874                        okay = false;
4875                    }
4876                } else {
4877                    // Okay, the install succeeded.  Make sure it was the right app.
4878                    boolean uninstall = false;
4879                    if (!mInstallObserver.mPackageName.equals(info.packageName)) {
4880                        Slog.w(TAG, "Restore stream claimed to include apk for "
4881                                + info.packageName + " but apk was really "
4882                                + mInstallObserver.mPackageName);
4883                        // delete the package we just put in place; it might be fraudulent
4884                        okay = false;
4885                        uninstall = true;
4886                    } else {
4887                        try {
4888                            PackageInfo pkg = mPackageManager.getPackageInfo(info.packageName,
4889                                    PackageManager.GET_SIGNATURES);
4890                            if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) {
4891                                Slog.w(TAG, "Restore stream contains apk of package "
4892                                        + info.packageName + " but it disallows backup/restore");
4893                                okay = false;
4894                            } else {
4895                                // So far so good -- do the signatures match the manifest?
4896                                Signature[] sigs = mManifestSignatures.get(info.packageName);
4897                                if (signaturesMatch(sigs, pkg)) {
4898                                    // If this is a system-uid app without a declared backup agent,
4899                                    // don't restore any of the file data.
4900                                    if ((pkg.applicationInfo.uid < Process.FIRST_APPLICATION_UID)
4901                                            && (pkg.applicationInfo.backupAgentName == null)) {
4902                                        Slog.w(TAG, "Installed app " + info.packageName
4903                                                + " has restricted uid and no agent");
4904                                        okay = false;
4905                                    }
4906                                } else {
4907                                    Slog.w(TAG, "Installed app " + info.packageName
4908                                            + " signatures do not match restore manifest");
4909                                    okay = false;
4910                                    uninstall = true;
4911                                }
4912                            }
4913                        } catch (NameNotFoundException e) {
4914                            Slog.w(TAG, "Install of package " + info.packageName
4915                                    + " succeeded but now not found");
4916                            okay = false;
4917                        }
4918                    }
4919
4920                    // If we're not okay at this point, we need to delete the package
4921                    // that we just installed.
4922                    if (uninstall) {
4923                        mDeleteObserver.reset();
4924                        mPackageManager.deletePackage(mInstallObserver.mPackageName,
4925                                mDeleteObserver, 0);
4926                        mDeleteObserver.waitForCompletion();
4927                    }
4928                }
4929            } catch (IOException e) {
4930                Slog.e(TAG, "Unable to transcribe restored apk for install");
4931                okay = false;
4932            } finally {
4933                apkFile.delete();
4934            }
4935
4936            return okay;
4937        }
4938
4939        // Given an actual file content size, consume the post-content padding mandated
4940        // by the tar format.
4941        void skipTarPadding(long size, InputStream instream) throws IOException {
4942            long partial = (size + 512) % 512;
4943            if (partial > 0) {
4944                final int needed = 512 - (int)partial;
4945                if (MORE_DEBUG) {
4946                    Slog.i(TAG, "Skipping tar padding: " + needed + " bytes");
4947                }
4948                byte[] buffer = new byte[needed];
4949                if (readExactly(instream, buffer, 0, needed) == needed) {
4950                    mBytes += needed;
4951                } else throw new IOException("Unexpected EOF in padding");
4952            }
4953        }
4954
4955        // Read a widget metadata file, returning the restored blob
4956        void readMetadata(FileMetadata info, InputStream instream) throws IOException {
4957            // Fail on suspiciously large widget dump files
4958            if (info.size > 64 * 1024) {
4959                throw new IOException("Metadata too big; corrupt? size=" + info.size);
4960            }
4961
4962            byte[] buffer = new byte[(int) info.size];
4963            if (readExactly(instream, buffer, 0, (int)info.size) == info.size) {
4964                mBytes += info.size;
4965            } else throw new IOException("Unexpected EOF in widget data");
4966
4967            String[] str = new String[1];
4968            int offset = extractLine(buffer, 0, str);
4969            int version = Integer.parseInt(str[0]);
4970            if (version == BACKUP_MANIFEST_VERSION) {
4971                offset = extractLine(buffer, offset, str);
4972                final String pkg = str[0];
4973                if (info.packageName.equals(pkg)) {
4974                    // Data checks out -- the rest of the buffer is a concatenation of
4975                    // binary blobs as described in the comment at writeAppWidgetData()
4976                    ByteArrayInputStream bin = new ByteArrayInputStream(buffer,
4977                            offset, buffer.length - offset);
4978                    DataInputStream in = new DataInputStream(bin);
4979                    while (bin.available() > 0) {
4980                        int token = in.readInt();
4981                        int size = in.readInt();
4982                        if (size > 64 * 1024) {
4983                            throw new IOException("Datum "
4984                                    + Integer.toHexString(token)
4985                                    + " too big; corrupt? size=" + info.size);
4986                        }
4987                        switch (token) {
4988                            case BACKUP_WIDGET_METADATA_TOKEN:
4989                            {
4990                                if (MORE_DEBUG) {
4991                                    Slog.i(TAG, "Got widget metadata for " + info.packageName);
4992                                }
4993                                mWidgetData = new byte[size];
4994                                in.read(mWidgetData);
4995                                break;
4996                            }
4997                            default:
4998                            {
4999                                if (DEBUG) {
5000                                    Slog.i(TAG, "Ignoring metadata blob "
5001                                            + Integer.toHexString(token)
5002                                            + " for " + info.packageName);
5003                                }
5004                                in.skipBytes(size);
5005                                break;
5006                            }
5007                        }
5008                    }
5009                } else {
5010                    Slog.w(TAG, "Metadata mismatch: package " + info.packageName
5011                            + " but widget data for " + pkg);
5012                }
5013            } else {
5014                Slog.w(TAG, "Unsupported metadata version " + version);
5015            }
5016        }
5017
5018        // Returns a policy constant
5019        RestorePolicy readAppManifest(FileMetadata info, InputStream instream)
5020                throws IOException {
5021            // Fail on suspiciously large manifest files
5022            if (info.size > 64 * 1024) {
5023                throw new IOException("Restore manifest too big; corrupt? size=" + info.size);
5024            }
5025
5026            byte[] buffer = new byte[(int) info.size];
5027            if (MORE_DEBUG) {
5028                Slog.i(TAG, "   readAppManifest() looking for " + info.size + " bytes, "
5029                        + mBytes + " already consumed");
5030            }
5031            if (readExactly(instream, buffer, 0, (int)info.size) == info.size) {
5032                mBytes += info.size;
5033            } else throw new IOException("Unexpected EOF in manifest");
5034
5035            RestorePolicy policy = RestorePolicy.IGNORE;
5036            String[] str = new String[1];
5037            int offset = 0;
5038
5039            try {
5040                offset = extractLine(buffer, offset, str);
5041                int version = Integer.parseInt(str[0]);
5042                if (version == BACKUP_MANIFEST_VERSION) {
5043                    offset = extractLine(buffer, offset, str);
5044                    String manifestPackage = str[0];
5045                    // TODO: handle <original-package>
5046                    if (manifestPackage.equals(info.packageName)) {
5047                        offset = extractLine(buffer, offset, str);
5048                        version = Integer.parseInt(str[0]);  // app version
5049                        offset = extractLine(buffer, offset, str);
5050                        int platformVersion = Integer.parseInt(str[0]);
5051                        offset = extractLine(buffer, offset, str);
5052                        info.installerPackageName = (str[0].length() > 0) ? str[0] : null;
5053                        offset = extractLine(buffer, offset, str);
5054                        boolean hasApk = str[0].equals("1");
5055                        offset = extractLine(buffer, offset, str);
5056                        int numSigs = Integer.parseInt(str[0]);
5057                        if (numSigs > 0) {
5058                            Signature[] sigs = new Signature[numSigs];
5059                            for (int i = 0; i < numSigs; i++) {
5060                                offset = extractLine(buffer, offset, str);
5061                                sigs[i] = new Signature(str[0]);
5062                            }
5063                            mManifestSignatures.put(info.packageName, sigs);
5064
5065                            // Okay, got the manifest info we need...
5066                            try {
5067                                PackageInfo pkgInfo = mPackageManager.getPackageInfo(
5068                                        info.packageName, PackageManager.GET_SIGNATURES);
5069                                // Fall through to IGNORE if the app explicitly disallows backup
5070                                final int flags = pkgInfo.applicationInfo.flags;
5071                                if ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0) {
5072                                    // Restore system-uid-space packages only if they have
5073                                    // defined a custom backup agent
5074                                    if ((pkgInfo.applicationInfo.uid >= Process.FIRST_APPLICATION_UID)
5075                                            || (pkgInfo.applicationInfo.backupAgentName != null)) {
5076                                        // Verify signatures against any installed version; if they
5077                                        // don't match, then we fall though and ignore the data.  The
5078                                        // signatureMatch() method explicitly ignores the signature
5079                                        // check for packages installed on the system partition, because
5080                                        // such packages are signed with the platform cert instead of
5081                                        // the app developer's cert, so they're different on every
5082                                        // device.
5083                                        if (signaturesMatch(sigs, pkgInfo)) {
5084                                            if (pkgInfo.versionCode >= version) {
5085                                                Slog.i(TAG, "Sig + version match; taking data");
5086                                                policy = RestorePolicy.ACCEPT;
5087                                            } else {
5088                                                // The data is from a newer version of the app than
5089                                                // is presently installed.  That means we can only
5090                                                // use it if the matching apk is also supplied.
5091                                                if (mAllowApks) {
5092                                                    Slog.i(TAG, "Data version " + version
5093                                                            + " is newer than installed version "
5094                                                            + pkgInfo.versionCode
5095                                                            + " - requiring apk");
5096                                                    policy = RestorePolicy.ACCEPT_IF_APK;
5097                                                } else {
5098                                                    Slog.i(TAG, "Data requires newer version "
5099                                                            + version + "; ignoring");
5100                                                    policy = RestorePolicy.IGNORE;
5101                                                }
5102                                            }
5103                                        } else {
5104                                            Slog.w(TAG, "Restore manifest signatures do not match "
5105                                                    + "installed application for " + info.packageName);
5106                                        }
5107                                    } else {
5108                                        Slog.w(TAG, "Package " + info.packageName
5109                                                + " is system level with no agent");
5110                                    }
5111                                } else {
5112                                    if (DEBUG) Slog.i(TAG, "Restore manifest from "
5113                                            + info.packageName + " but allowBackup=false");
5114                                }
5115                            } catch (NameNotFoundException e) {
5116                                // Okay, the target app isn't installed.  We can process
5117                                // the restore properly only if the dataset provides the
5118                                // apk file and we can successfully install it.
5119                                if (mAllowApks) {
5120                                    if (DEBUG) Slog.i(TAG, "Package " + info.packageName
5121                                            + " not installed; requiring apk in dataset");
5122                                    policy = RestorePolicy.ACCEPT_IF_APK;
5123                                } else {
5124                                    policy = RestorePolicy.IGNORE;
5125                                }
5126                            }
5127
5128                            if (policy == RestorePolicy.ACCEPT_IF_APK && !hasApk) {
5129                                Slog.i(TAG, "Cannot restore package " + info.packageName
5130                                        + " without the matching .apk");
5131                            }
5132                        } else {
5133                            Slog.i(TAG, "Missing signature on backed-up package "
5134                                    + info.packageName);
5135                        }
5136                    } else {
5137                        Slog.i(TAG, "Expected package " + info.packageName
5138                                + " but restore manifest claims " + manifestPackage);
5139                    }
5140                } else {
5141                    Slog.i(TAG, "Unknown restore manifest version " + version
5142                            + " for package " + info.packageName);
5143                }
5144            } catch (NumberFormatException e) {
5145                Slog.w(TAG, "Corrupt restore manifest for package " + info.packageName);
5146            } catch (IllegalArgumentException e) {
5147                Slog.w(TAG, e.getMessage());
5148            }
5149
5150            return policy;
5151        }
5152
5153        // Builds a line from a byte buffer starting at 'offset', and returns
5154        // the index of the next unconsumed data in the buffer.
5155        int extractLine(byte[] buffer, int offset, String[] outStr) throws IOException {
5156            final int end = buffer.length;
5157            if (offset >= end) throw new IOException("Incomplete data");
5158
5159            int pos;
5160            for (pos = offset; pos < end; pos++) {
5161                byte c = buffer[pos];
5162                // at LF we declare end of line, and return the next char as the
5163                // starting point for the next time through
5164                if (c == '\n') {
5165                    break;
5166                }
5167            }
5168            outStr[0] = new String(buffer, offset, pos - offset);
5169            pos++;  // may be pointing an extra byte past the end but that's okay
5170            return pos;
5171        }
5172
5173        void dumpFileMetadata(FileMetadata info) {
5174            if (DEBUG) {
5175                StringBuilder b = new StringBuilder(128);
5176
5177                // mode string
5178                b.append((info.type == BackupAgent.TYPE_DIRECTORY) ? 'd' : '-');
5179                b.append(((info.mode & 0400) != 0) ? 'r' : '-');
5180                b.append(((info.mode & 0200) != 0) ? 'w' : '-');
5181                b.append(((info.mode & 0100) != 0) ? 'x' : '-');
5182                b.append(((info.mode & 0040) != 0) ? 'r' : '-');
5183                b.append(((info.mode & 0020) != 0) ? 'w' : '-');
5184                b.append(((info.mode & 0010) != 0) ? 'x' : '-');
5185                b.append(((info.mode & 0004) != 0) ? 'r' : '-');
5186                b.append(((info.mode & 0002) != 0) ? 'w' : '-');
5187                b.append(((info.mode & 0001) != 0) ? 'x' : '-');
5188                b.append(String.format(" %9d ", info.size));
5189
5190                Date stamp = new Date(info.mtime);
5191                b.append(new SimpleDateFormat("MMM dd HH:mm:ss ").format(stamp));
5192
5193                b.append(info.packageName);
5194                b.append(" :: ");
5195                b.append(info.domain);
5196                b.append(" :: ");
5197                b.append(info.path);
5198
5199                Slog.i(TAG, b.toString());
5200            }
5201        }
5202
5203        // Consume a tar file header block [sequence] and accumulate the relevant metadata
5204        FileMetadata readTarHeaders(InputStream instream) throws IOException {
5205            byte[] block = new byte[512];
5206            FileMetadata info = null;
5207
5208            boolean gotHeader = readTarHeader(instream, block);
5209            if (gotHeader) {
5210                try {
5211                    // okay, presume we're okay, and extract the various metadata
5212                    info = new FileMetadata();
5213                    info.size = extractRadix(block, 124, 12, 8);
5214                    info.mtime = extractRadix(block, 136, 12, 8);
5215                    info.mode = extractRadix(block, 100, 8, 8);
5216
5217                    info.path = extractString(block, 345, 155); // prefix
5218                    String path = extractString(block, 0, 100);
5219                    if (path.length() > 0) {
5220                        if (info.path.length() > 0) info.path += '/';
5221                        info.path += path;
5222                    }
5223
5224                    // tar link indicator field: 1 byte at offset 156 in the header.
5225                    int typeChar = block[156];
5226                    if (typeChar == 'x') {
5227                        // pax extended header, so we need to read that
5228                        gotHeader = readPaxExtendedHeader(instream, info);
5229                        if (gotHeader) {
5230                            // and after a pax extended header comes another real header -- read
5231                            // that to find the real file type
5232                            gotHeader = readTarHeader(instream, block);
5233                        }
5234                        if (!gotHeader) throw new IOException("Bad or missing pax header");
5235
5236                        typeChar = block[156];
5237                    }
5238
5239                    switch (typeChar) {
5240                        case '0': info.type = BackupAgent.TYPE_FILE; break;
5241                        case '5': {
5242                            info.type = BackupAgent.TYPE_DIRECTORY;
5243                            if (info.size != 0) {
5244                                Slog.w(TAG, "Directory entry with nonzero size in header");
5245                                info.size = 0;
5246                            }
5247                            break;
5248                        }
5249                        case 0: {
5250                            // presume EOF
5251                            if (DEBUG) Slog.w(TAG, "Saw type=0 in tar header block, info=" + info);
5252                            return null;
5253                        }
5254                        default: {
5255                            Slog.e(TAG, "Unknown tar entity type: " + typeChar);
5256                            throw new IOException("Unknown entity type " + typeChar);
5257                        }
5258                    }
5259
5260                    // Parse out the path
5261                    //
5262                    // first: apps/shared/unrecognized
5263                    if (FullBackup.SHARED_PREFIX.regionMatches(0,
5264                            info.path, 0, FullBackup.SHARED_PREFIX.length())) {
5265                        // File in shared storage.  !!! TODO: implement this.
5266                        info.path = info.path.substring(FullBackup.SHARED_PREFIX.length());
5267                        info.packageName = SHARED_BACKUP_AGENT_PACKAGE;
5268                        info.domain = FullBackup.SHARED_STORAGE_TOKEN;
5269                        if (DEBUG) Slog.i(TAG, "File in shared storage: " + info.path);
5270                    } else if (FullBackup.APPS_PREFIX.regionMatches(0,
5271                            info.path, 0, FullBackup.APPS_PREFIX.length())) {
5272                        // App content!  Parse out the package name and domain
5273
5274                        // strip the apps/ prefix
5275                        info.path = info.path.substring(FullBackup.APPS_PREFIX.length());
5276
5277                        // extract the package name
5278                        int slash = info.path.indexOf('/');
5279                        if (slash < 0) throw new IOException("Illegal semantic path in " + info.path);
5280                        info.packageName = info.path.substring(0, slash);
5281                        info.path = info.path.substring(slash+1);
5282
5283                        // if it's a manifest or metadata payload we're done, otherwise parse
5284                        // out the domain into which the file will be restored
5285                        if (!info.path.equals(BACKUP_MANIFEST_FILENAME)
5286                                && !info.path.equals(BACKUP_METADATA_FILENAME)) {
5287                            slash = info.path.indexOf('/');
5288                            if (slash < 0) {
5289                                throw new IOException("Illegal semantic path in non-manifest "
5290                                        + info.path);
5291                            }
5292                            info.domain = info.path.substring(0, slash);
5293                            info.path = info.path.substring(slash + 1);
5294                        }
5295                    }
5296                } catch (IOException e) {
5297                    if (DEBUG) {
5298                        Slog.e(TAG, "Parse error in header: " + e.getMessage());
5299                        HEXLOG(block);
5300                    }
5301                    throw e;
5302                }
5303            }
5304            return info;
5305        }
5306
5307        private boolean isRestorableFile(FileMetadata info) {
5308            if (FullBackup.CACHE_TREE_TOKEN.equals(info.domain)) {
5309                if (MORE_DEBUG) {
5310                    Slog.i(TAG, "Dropping cache file path " + info.path);
5311                }
5312                return false;
5313            }
5314
5315            if (FullBackup.ROOT_TREE_TOKEN.equals(info.domain)) {
5316                // It's possible this is "no-backup" dir contents in an archive stream
5317                // produced on a device running a version of the OS that predates that
5318                // API.  Respect the no-backup intention and don't let the data get to
5319                // the app.
5320                if (info.path.startsWith("no_backup/")) {
5321                    if (MORE_DEBUG) {
5322                        Slog.i(TAG, "Dropping no_backup file path " + info.path);
5323                    }
5324                    return false;
5325                }
5326            }
5327
5328            // The path needs to be canonical
5329            if (info.path.contains("..") || info.path.contains("//")) {
5330                if (MORE_DEBUG) {
5331                    Slog.w(TAG, "Dropping invalid path " + info.path);
5332                }
5333                return false;
5334            }
5335
5336            // Otherwise we think this file is good to go
5337            return true;
5338        }
5339
5340        private void HEXLOG(byte[] block) {
5341            int offset = 0;
5342            int todo = block.length;
5343            StringBuilder buf = new StringBuilder(64);
5344            while (todo > 0) {
5345                buf.append(String.format("%04x   ", offset));
5346                int numThisLine = (todo > 16) ? 16 : todo;
5347                for (int i = 0; i < numThisLine; i++) {
5348                    buf.append(String.format("%02x ", block[offset+i]));
5349                }
5350                Slog.i("hexdump", buf.toString());
5351                buf.setLength(0);
5352                todo -= numThisLine;
5353                offset += numThisLine;
5354            }
5355        }
5356
5357        // Read exactly the given number of bytes into a buffer at the stated offset.
5358        // Returns false if EOF is encountered before the requested number of bytes
5359        // could be read.
5360        int readExactly(InputStream in, byte[] buffer, int offset, int size)
5361                throws IOException {
5362            if (size <= 0) throw new IllegalArgumentException("size must be > 0");
5363if (MORE_DEBUG) Slog.i(TAG, "  ... readExactly(" + size + ") called");
5364            int soFar = 0;
5365            while (soFar < size) {
5366                int nRead = in.read(buffer, offset + soFar, size - soFar);
5367                if (nRead <= 0) {
5368                    if (MORE_DEBUG) Slog.w(TAG, "- wanted exactly " + size + " but got only " + soFar);
5369                    break;
5370                }
5371                soFar += nRead;
5372if (MORE_DEBUG) Slog.v(TAG, "   + got " + nRead + "; now wanting " + (size - soFar));
5373            }
5374            return soFar;
5375        }
5376
5377        boolean readTarHeader(InputStream instream, byte[] block) throws IOException {
5378            final int got = readExactly(instream, block, 0, 512);
5379            if (got == 0) return false;     // Clean EOF
5380            if (got < 512) throw new IOException("Unable to read full block header");
5381            mBytes += 512;
5382            return true;
5383        }
5384
5385        // overwrites 'info' fields based on the pax extended header
5386        boolean readPaxExtendedHeader(InputStream instream, FileMetadata info)
5387                throws IOException {
5388            // We should never see a pax extended header larger than this
5389            if (info.size > 32*1024) {
5390                Slog.w(TAG, "Suspiciously large pax header size " + info.size
5391                        + " - aborting");
5392                throw new IOException("Sanity failure: pax header size " + info.size);
5393            }
5394
5395            // read whole blocks, not just the content size
5396            int numBlocks = (int)((info.size + 511) >> 9);
5397            byte[] data = new byte[numBlocks * 512];
5398            if (readExactly(instream, data, 0, data.length) < data.length) {
5399                throw new IOException("Unable to read full pax header");
5400            }
5401            mBytes += data.length;
5402
5403            final int contentSize = (int) info.size;
5404            int offset = 0;
5405            do {
5406                // extract the line at 'offset'
5407                int eol = offset+1;
5408                while (eol < contentSize && data[eol] != ' ') eol++;
5409                if (eol >= contentSize) {
5410                    // error: we just hit EOD looking for the end of the size field
5411                    throw new IOException("Invalid pax data");
5412                }
5413                // eol points to the space between the count and the key
5414                int linelen = (int) extractRadix(data, offset, eol - offset, 10);
5415                int key = eol + 1;  // start of key=value
5416                eol = offset + linelen - 1; // trailing LF
5417                int value;
5418                for (value = key+1; data[value] != '=' && value <= eol; value++);
5419                if (value > eol) {
5420                    throw new IOException("Invalid pax declaration");
5421                }
5422
5423                // pax requires that key/value strings be in UTF-8
5424                String keyStr = new String(data, key, value-key, "UTF-8");
5425                // -1 to strip the trailing LF
5426                String valStr = new String(data, value+1, eol-value-1, "UTF-8");
5427
5428                if ("path".equals(keyStr)) {
5429                    info.path = valStr;
5430                } else if ("size".equals(keyStr)) {
5431                    info.size = Long.parseLong(valStr);
5432                } else {
5433                    if (DEBUG) Slog.i(TAG, "Unhandled pax key: " + key);
5434                }
5435
5436                offset += linelen;
5437            } while (offset < contentSize);
5438
5439            return true;
5440        }
5441
5442        long extractRadix(byte[] data, int offset, int maxChars, int radix)
5443                throws IOException {
5444            long value = 0;
5445            final int end = offset + maxChars;
5446            for (int i = offset; i < end; i++) {
5447                final byte b = data[i];
5448                // Numeric fields in tar can terminate with either NUL or SPC
5449                if (b == 0 || b == ' ') break;
5450                if (b < '0' || b > ('0' + radix - 1)) {
5451                    throw new IOException("Invalid number in header: '" + (char)b
5452                            + "' for radix " + radix);
5453                }
5454                value = radix * value + (b - '0');
5455            }
5456            return value;
5457        }
5458
5459        String extractString(byte[] data, int offset, int maxChars) throws IOException {
5460            final int end = offset + maxChars;
5461            int eos = offset;
5462            // tar string fields terminate early with a NUL
5463            while (eos < end && data[eos] != 0) eos++;
5464            return new String(data, offset, eos-offset, "US-ASCII");
5465        }
5466
5467        void sendStartRestore() {
5468            if (mObserver != null) {
5469                try {
5470                    mObserver.onStartRestore();
5471                } catch (RemoteException e) {
5472                    Slog.w(TAG, "full restore observer went away: startRestore");
5473                    mObserver = null;
5474                }
5475            }
5476        }
5477
5478        void sendOnRestorePackage(String name) {
5479            if (mObserver != null) {
5480                try {
5481                    // TODO: use a more user-friendly name string
5482                    mObserver.onRestorePackage(name);
5483                } catch (RemoteException e) {
5484                    Slog.w(TAG, "full restore observer went away: restorePackage");
5485                    mObserver = null;
5486                }
5487            }
5488        }
5489
5490        void sendEndRestore() {
5491            if (mObserver != null) {
5492                try {
5493                    mObserver.onEndRestore();
5494                } catch (RemoteException e) {
5495                    Slog.w(TAG, "full restore observer went away: endRestore");
5496                    mObserver = null;
5497                }
5498            }
5499        }
5500    }
5501
5502    // ***** end new engine class ***
5503
5504    class PerformAdbRestoreTask implements Runnable {
5505        ParcelFileDescriptor mInputFile;
5506        String mCurrentPassword;
5507        String mDecryptPassword;
5508        IFullBackupRestoreObserver mObserver;
5509        AtomicBoolean mLatchObject;
5510        IBackupAgent mAgent;
5511        String mAgentPackage;
5512        ApplicationInfo mTargetApp;
5513        FullBackupObbConnection mObbConnection = null;
5514        ParcelFileDescriptor[] mPipes = null;
5515        byte[] mWidgetData = null;
5516
5517        long mBytes;
5518
5519        // possible handling states for a given package in the restore dataset
5520        final HashMap<String, RestorePolicy> mPackagePolicies
5521                = new HashMap<String, RestorePolicy>();
5522
5523        // installer package names for each encountered app, derived from the manifests
5524        final HashMap<String, String> mPackageInstallers = new HashMap<String, String>();
5525
5526        // Signatures for a given package found in its manifest file
5527        final HashMap<String, Signature[]> mManifestSignatures
5528                = new HashMap<String, Signature[]>();
5529
5530        // Packages we've already wiped data on when restoring their first file
5531        final HashSet<String> mClearedPackages = new HashSet<String>();
5532
5533        PerformAdbRestoreTask(ParcelFileDescriptor fd, String curPassword, String decryptPassword,
5534                IFullBackupRestoreObserver observer, AtomicBoolean latch) {
5535            mInputFile = fd;
5536            mCurrentPassword = curPassword;
5537            mDecryptPassword = decryptPassword;
5538            mObserver = observer;
5539            mLatchObject = latch;
5540            mAgent = null;
5541            mAgentPackage = null;
5542            mTargetApp = null;
5543            mObbConnection = new FullBackupObbConnection();
5544
5545            // Which packages we've already wiped data on.  We prepopulate this
5546            // with a whitelist of packages known to be unclearable.
5547            mClearedPackages.add("android");
5548            mClearedPackages.add(SETTINGS_PACKAGE);
5549        }
5550
5551        class RestoreFileRunnable implements Runnable {
5552            IBackupAgent mAgent;
5553            FileMetadata mInfo;
5554            ParcelFileDescriptor mSocket;
5555            int mToken;
5556
5557            RestoreFileRunnable(IBackupAgent agent, FileMetadata info,
5558                    ParcelFileDescriptor socket, int token) throws IOException {
5559                mAgent = agent;
5560                mInfo = info;
5561                mToken = token;
5562
5563                // This class is used strictly for process-local binder invocations.  The
5564                // semantics of ParcelFileDescriptor differ in this case; in particular, we
5565                // do not automatically get a 'dup'ed descriptor that we can can continue
5566                // to use asynchronously from the caller.  So, we make sure to dup it ourselves
5567                // before proceeding to do the restore.
5568                mSocket = ParcelFileDescriptor.dup(socket.getFileDescriptor());
5569            }
5570
5571            @Override
5572            public void run() {
5573                try {
5574                    mAgent.doRestoreFile(mSocket, mInfo.size, mInfo.type,
5575                            mInfo.domain, mInfo.path, mInfo.mode, mInfo.mtime,
5576                            mToken, mBackupManagerBinder);
5577                } catch (RemoteException e) {
5578                    // never happens; this is used strictly for local binder calls
5579                }
5580            }
5581        }
5582
5583        @Override
5584        public void run() {
5585            Slog.i(TAG, "--- Performing full-dataset restore ---");
5586            mObbConnection.establish();
5587            sendStartRestore();
5588
5589            // Are we able to restore shared-storage data?
5590            if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
5591                mPackagePolicies.put(SHARED_BACKUP_AGENT_PACKAGE, RestorePolicy.ACCEPT);
5592            }
5593
5594            FileInputStream rawInStream = null;
5595            DataInputStream rawDataIn = null;
5596            try {
5597                if (!backupPasswordMatches(mCurrentPassword)) {
5598                    if (DEBUG) Slog.w(TAG, "Backup password mismatch; aborting");
5599                    return;
5600                }
5601
5602                mBytes = 0;
5603                byte[] buffer = new byte[32 * 1024];
5604                rawInStream = new FileInputStream(mInputFile.getFileDescriptor());
5605                rawDataIn = new DataInputStream(rawInStream);
5606
5607                // First, parse out the unencrypted/uncompressed header
5608                boolean compressed = false;
5609                InputStream preCompressStream = rawInStream;
5610                final InputStream in;
5611
5612                boolean okay = false;
5613                final int headerLen = BACKUP_FILE_HEADER_MAGIC.length();
5614                byte[] streamHeader = new byte[headerLen];
5615                rawDataIn.readFully(streamHeader);
5616                byte[] magicBytes = BACKUP_FILE_HEADER_MAGIC.getBytes("UTF-8");
5617                if (Arrays.equals(magicBytes, streamHeader)) {
5618                    // okay, header looks good.  now parse out the rest of the fields.
5619                    String s = readHeaderLine(rawInStream);
5620                    final int archiveVersion = Integer.parseInt(s);
5621                    if (archiveVersion <= BACKUP_FILE_VERSION) {
5622                        // okay, it's a version we recognize.  if it's version 1, we may need
5623                        // to try two different PBKDF2 regimes to compare checksums.
5624                        final boolean pbkdf2Fallback = (archiveVersion == 1);
5625
5626                        s = readHeaderLine(rawInStream);
5627                        compressed = (Integer.parseInt(s) != 0);
5628                        s = readHeaderLine(rawInStream);
5629                        if (s.equals("none")) {
5630                            // no more header to parse; we're good to go
5631                            okay = true;
5632                        } else if (mDecryptPassword != null && mDecryptPassword.length() > 0) {
5633                            preCompressStream = decodeAesHeaderAndInitialize(s, pbkdf2Fallback,
5634                                    rawInStream);
5635                            if (preCompressStream != null) {
5636                                okay = true;
5637                            }
5638                        } else Slog.w(TAG, "Archive is encrypted but no password given");
5639                    } else Slog.w(TAG, "Wrong header version: " + s);
5640                } else Slog.w(TAG, "Didn't read the right header magic");
5641
5642                if (!okay) {
5643                    Slog.w(TAG, "Invalid restore data; aborting.");
5644                    return;
5645                }
5646
5647                // okay, use the right stream layer based on compression
5648                in = (compressed) ? new InflaterInputStream(preCompressStream) : preCompressStream;
5649
5650                boolean didRestore;
5651                do {
5652                    didRestore = restoreOneFile(in, buffer);
5653                } while (didRestore);
5654
5655                if (MORE_DEBUG) Slog.v(TAG, "Done consuming input tarfile, total bytes=" + mBytes);
5656            } catch (IOException e) {
5657                Slog.e(TAG, "Unable to read restore input");
5658            } finally {
5659                tearDownPipes();
5660                tearDownAgent(mTargetApp);
5661
5662                try {
5663                    if (rawDataIn != null) rawDataIn.close();
5664                    if (rawInStream != null) rawInStream.close();
5665                    mInputFile.close();
5666                } catch (IOException e) {
5667                    Slog.w(TAG, "Close of restore data pipe threw", e);
5668                    /* nothing we can do about this */
5669                }
5670                synchronized (mCurrentOpLock) {
5671                    mCurrentOperations.clear();
5672                }
5673                synchronized (mLatchObject) {
5674                    mLatchObject.set(true);
5675                    mLatchObject.notifyAll();
5676                }
5677                mObbConnection.tearDown();
5678                sendEndRestore();
5679                Slog.d(TAG, "Full restore pass complete.");
5680                mWakelock.release();
5681            }
5682        }
5683
5684        String readHeaderLine(InputStream in) throws IOException {
5685            int c;
5686            StringBuilder buffer = new StringBuilder(80);
5687            while ((c = in.read()) >= 0) {
5688                if (c == '\n') break;   // consume and discard the newlines
5689                buffer.append((char)c);
5690            }
5691            return buffer.toString();
5692        }
5693
5694        InputStream attemptMasterKeyDecryption(String algorithm, byte[] userSalt, byte[] ckSalt,
5695                int rounds, String userIvHex, String masterKeyBlobHex, InputStream rawInStream,
5696                boolean doLog) {
5697            InputStream result = null;
5698
5699            try {
5700                Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
5701                SecretKey userKey = buildPasswordKey(algorithm, mDecryptPassword, userSalt,
5702                        rounds);
5703                byte[] IV = hexToByteArray(userIvHex);
5704                IvParameterSpec ivSpec = new IvParameterSpec(IV);
5705                c.init(Cipher.DECRYPT_MODE,
5706                        new SecretKeySpec(userKey.getEncoded(), "AES"),
5707                        ivSpec);
5708                byte[] mkCipher = hexToByteArray(masterKeyBlobHex);
5709                byte[] mkBlob = c.doFinal(mkCipher);
5710
5711                // first, the master key IV
5712                int offset = 0;
5713                int len = mkBlob[offset++];
5714                IV = Arrays.copyOfRange(mkBlob, offset, offset + len);
5715                offset += len;
5716                // then the master key itself
5717                len = mkBlob[offset++];
5718                byte[] mk = Arrays.copyOfRange(mkBlob,
5719                        offset, offset + len);
5720                offset += len;
5721                // and finally the master key checksum hash
5722                len = mkBlob[offset++];
5723                byte[] mkChecksum = Arrays.copyOfRange(mkBlob,
5724                        offset, offset + len);
5725
5726                // now validate the decrypted master key against the checksum
5727                byte[] calculatedCk = makeKeyChecksum(algorithm, mk, ckSalt, rounds);
5728                if (Arrays.equals(calculatedCk, mkChecksum)) {
5729                    ivSpec = new IvParameterSpec(IV);
5730                    c.init(Cipher.DECRYPT_MODE,
5731                            new SecretKeySpec(mk, "AES"),
5732                            ivSpec);
5733                    // Only if all of the above worked properly will 'result' be assigned
5734                    result = new CipherInputStream(rawInStream, c);
5735                } else if (doLog) Slog.w(TAG, "Incorrect password");
5736            } catch (InvalidAlgorithmParameterException e) {
5737                if (doLog) Slog.e(TAG, "Needed parameter spec unavailable!", e);
5738            } catch (BadPaddingException e) {
5739                // This case frequently occurs when the wrong password is used to decrypt
5740                // the master key.  Use the identical "incorrect password" log text as is
5741                // used in the checksum failure log in order to avoid providing additional
5742                // information to an attacker.
5743                if (doLog) Slog.w(TAG, "Incorrect password");
5744            } catch (IllegalBlockSizeException e) {
5745                if (doLog) Slog.w(TAG, "Invalid block size in master key");
5746            } catch (NoSuchAlgorithmException e) {
5747                if (doLog) Slog.e(TAG, "Needed decryption algorithm unavailable!");
5748            } catch (NoSuchPaddingException e) {
5749                if (doLog) Slog.e(TAG, "Needed padding mechanism unavailable!");
5750            } catch (InvalidKeyException e) {
5751                if (doLog) Slog.w(TAG, "Illegal password; aborting");
5752            }
5753
5754            return result;
5755        }
5756
5757        InputStream decodeAesHeaderAndInitialize(String encryptionName, boolean pbkdf2Fallback,
5758                InputStream rawInStream) {
5759            InputStream result = null;
5760            try {
5761                if (encryptionName.equals(ENCRYPTION_ALGORITHM_NAME)) {
5762
5763                    String userSaltHex = readHeaderLine(rawInStream); // 5
5764                    byte[] userSalt = hexToByteArray(userSaltHex);
5765
5766                    String ckSaltHex = readHeaderLine(rawInStream); // 6
5767                    byte[] ckSalt = hexToByteArray(ckSaltHex);
5768
5769                    int rounds = Integer.parseInt(readHeaderLine(rawInStream)); // 7
5770                    String userIvHex = readHeaderLine(rawInStream); // 8
5771
5772                    String masterKeyBlobHex = readHeaderLine(rawInStream); // 9
5773
5774                    // decrypt the master key blob
5775                    result = attemptMasterKeyDecryption(PBKDF_CURRENT, userSalt, ckSalt,
5776                            rounds, userIvHex, masterKeyBlobHex, rawInStream, false);
5777                    if (result == null && pbkdf2Fallback) {
5778                        result = attemptMasterKeyDecryption(PBKDF_FALLBACK, userSalt, ckSalt,
5779                                rounds, userIvHex, masterKeyBlobHex, rawInStream, true);
5780                    }
5781                } else Slog.w(TAG, "Unsupported encryption method: " + encryptionName);
5782            } catch (NumberFormatException e) {
5783                Slog.w(TAG, "Can't parse restore data header");
5784            } catch (IOException e) {
5785                Slog.w(TAG, "Can't read input header");
5786            }
5787
5788            return result;
5789        }
5790
5791        boolean restoreOneFile(InputStream instream, byte[] buffer) {
5792            FileMetadata info;
5793            try {
5794                info = readTarHeaders(instream);
5795                if (info != null) {
5796                    if (MORE_DEBUG) {
5797                        dumpFileMetadata(info);
5798                    }
5799
5800                    final String pkg = info.packageName;
5801                    if (!pkg.equals(mAgentPackage)) {
5802                        // okay, change in package; set up our various
5803                        // bookkeeping if we haven't seen it yet
5804                        if (!mPackagePolicies.containsKey(pkg)) {
5805                            mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
5806                        }
5807
5808                        // Clean up the previous agent relationship if necessary,
5809                        // and let the observer know we're considering a new app.
5810                        if (mAgent != null) {
5811                            if (DEBUG) Slog.d(TAG, "Saw new package; finalizing old one");
5812                            // Now we're really done
5813                            tearDownPipes();
5814                            tearDownAgent(mTargetApp);
5815                            mTargetApp = null;
5816                            mAgentPackage = null;
5817                        }
5818                    }
5819
5820                    if (info.path.equals(BACKUP_MANIFEST_FILENAME)) {
5821                        mPackagePolicies.put(pkg, readAppManifest(info, instream));
5822                        mPackageInstallers.put(pkg, info.installerPackageName);
5823                        // We've read only the manifest content itself at this point,
5824                        // so consume the footer before looping around to the next
5825                        // input file
5826                        skipTarPadding(info.size, instream);
5827                        sendOnRestorePackage(pkg);
5828                    } else if (info.path.equals(BACKUP_METADATA_FILENAME)) {
5829                        // Metadata blobs!
5830                        readMetadata(info, instream);
5831                        skipTarPadding(info.size, instream);
5832                    } else {
5833                        // Non-manifest, so it's actual file data.  Is this a package
5834                        // we're ignoring?
5835                        boolean okay = true;
5836                        RestorePolicy policy = mPackagePolicies.get(pkg);
5837                        switch (policy) {
5838                            case IGNORE:
5839                                okay = false;
5840                                break;
5841
5842                            case ACCEPT_IF_APK:
5843                                // If we're in accept-if-apk state, then the first file we
5844                                // see MUST be the apk.
5845                                if (info.domain.equals(FullBackup.APK_TREE_TOKEN)) {
5846                                    if (DEBUG) Slog.d(TAG, "APK file; installing");
5847                                    // Try to install the app.
5848                                    String installerName = mPackageInstallers.get(pkg);
5849                                    okay = installApk(info, installerName, instream);
5850                                    // good to go; promote to ACCEPT
5851                                    mPackagePolicies.put(pkg, (okay)
5852                                            ? RestorePolicy.ACCEPT
5853                                            : RestorePolicy.IGNORE);
5854                                    // At this point we've consumed this file entry
5855                                    // ourselves, so just strip the tar footer and
5856                                    // go on to the next file in the input stream
5857                                    skipTarPadding(info.size, instream);
5858                                    return true;
5859                                } else {
5860                                    // File data before (or without) the apk.  We can't
5861                                    // handle it coherently in this case so ignore it.
5862                                    mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
5863                                    okay = false;
5864                                }
5865                                break;
5866
5867                            case ACCEPT:
5868                                if (info.domain.equals(FullBackup.APK_TREE_TOKEN)) {
5869                                    if (DEBUG) Slog.d(TAG, "apk present but ACCEPT");
5870                                    // we can take the data without the apk, so we
5871                                    // *want* to do so.  skip the apk by declaring this
5872                                    // one file not-okay without changing the restore
5873                                    // policy for the package.
5874                                    okay = false;
5875                                }
5876                                break;
5877
5878                            default:
5879                                // Something has gone dreadfully wrong when determining
5880                                // the restore policy from the manifest.  Ignore the
5881                                // rest of this package's data.
5882                                Slog.e(TAG, "Invalid policy from manifest");
5883                                okay = false;
5884                                mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
5885                                break;
5886                        }
5887
5888                        // The path needs to be canonical
5889                        if (info.path.contains("..") || info.path.contains("//")) {
5890                            if (MORE_DEBUG) {
5891                                Slog.w(TAG, "Dropping invalid path " + info.path);
5892                            }
5893                            okay = false;
5894                        }
5895
5896                        // If the policy is satisfied, go ahead and set up to pipe the
5897                        // data to the agent.
5898                        if (DEBUG && okay && mAgent != null) {
5899                            Slog.i(TAG, "Reusing existing agent instance");
5900                        }
5901                        if (okay && mAgent == null) {
5902                            if (DEBUG) Slog.d(TAG, "Need to launch agent for " + pkg);
5903
5904                            try {
5905                                mTargetApp = mPackageManager.getApplicationInfo(pkg, 0);
5906
5907                                // If we haven't sent any data to this app yet, we probably
5908                                // need to clear it first.  Check that.
5909                                if (!mClearedPackages.contains(pkg)) {
5910                                    // apps with their own backup agents are
5911                                    // responsible for coherently managing a full
5912                                    // restore.
5913                                    if (mTargetApp.backupAgentName == null) {
5914                                        if (DEBUG) Slog.d(TAG, "Clearing app data preparatory to full restore");
5915                                        clearApplicationDataSynchronous(pkg);
5916                                    } else {
5917                                        if (DEBUG) Slog.d(TAG, "backup agent ("
5918                                                + mTargetApp.backupAgentName + ") => no clear");
5919                                    }
5920                                    mClearedPackages.add(pkg);
5921                                } else {
5922                                    if (DEBUG) Slog.d(TAG, "We've initialized this app already; no clear required");
5923                                }
5924
5925                                // All set; now set up the IPC and launch the agent
5926                                setUpPipes();
5927                                mAgent = bindToAgentSynchronous(mTargetApp,
5928                                        IApplicationThread.BACKUP_MODE_RESTORE_FULL);
5929                                mAgentPackage = pkg;
5930                            } catch (IOException e) {
5931                                // fall through to error handling
5932                            } catch (NameNotFoundException e) {
5933                                // fall through to error handling
5934                            }
5935
5936                            if (mAgent == null) {
5937                                if (DEBUG) Slog.d(TAG, "Unable to create agent for " + pkg);
5938                                okay = false;
5939                                tearDownPipes();
5940                                mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
5941                            }
5942                        }
5943
5944                        // Sanity check: make sure we never give data to the wrong app.  This
5945                        // should never happen but a little paranoia here won't go amiss.
5946                        if (okay && !pkg.equals(mAgentPackage)) {
5947                            Slog.e(TAG, "Restoring data for " + pkg
5948                                    + " but agent is for " + mAgentPackage);
5949                            okay = false;
5950                        }
5951
5952                        // At this point we have an agent ready to handle the full
5953                        // restore data as well as a pipe for sending data to
5954                        // that agent.  Tell the agent to start reading from the
5955                        // pipe.
5956                        if (okay) {
5957                            boolean agentSuccess = true;
5958                            long toCopy = info.size;
5959                            final int token = generateToken();
5960                            try {
5961                                prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL, null);
5962                                if (info.domain.equals(FullBackup.OBB_TREE_TOKEN)) {
5963                                    if (DEBUG) Slog.d(TAG, "Restoring OBB file for " + pkg
5964                                            + " : " + info.path);
5965                                    mObbConnection.restoreObbFile(pkg, mPipes[0],
5966                                            info.size, info.type, info.path, info.mode,
5967                                            info.mtime, token, mBackupManagerBinder);
5968                                } else {
5969                                    if (DEBUG) Slog.d(TAG, "Invoking agent to restore file "
5970                                            + info.path);
5971                                    // fire up the app's agent listening on the socket.  If
5972                                    // the agent is running in the system process we can't
5973                                    // just invoke it asynchronously, so we provide a thread
5974                                    // for it here.
5975                                    if (mTargetApp.processName.equals("system")) {
5976                                        Slog.d(TAG, "system process agent - spinning a thread");
5977                                        RestoreFileRunnable runner = new RestoreFileRunnable(
5978                                                mAgent, info, mPipes[0], token);
5979                                        new Thread(runner, "restore-sys-runner").start();
5980                                    } else {
5981                                        mAgent.doRestoreFile(mPipes[0], info.size, info.type,
5982                                                info.domain, info.path, info.mode, info.mtime,
5983                                                token, mBackupManagerBinder);
5984                                    }
5985                                }
5986                            } catch (IOException e) {
5987                                // couldn't dup the socket for a process-local restore
5988                                Slog.d(TAG, "Couldn't establish restore");
5989                                agentSuccess = false;
5990                                okay = false;
5991                            } catch (RemoteException e) {
5992                                // whoops, remote entity went away.  We'll eat the content
5993                                // ourselves, then, and not copy it over.
5994                                Slog.e(TAG, "Agent crashed during full restore");
5995                                agentSuccess = false;
5996                                okay = false;
5997                            }
5998
5999                            // Copy over the data if the agent is still good
6000                            if (okay) {
6001                                boolean pipeOkay = true;
6002                                FileOutputStream pipe = new FileOutputStream(
6003                                        mPipes[1].getFileDescriptor());
6004                                while (toCopy > 0) {
6005                                    int toRead = (toCopy > buffer.length)
6006                                    ? buffer.length : (int)toCopy;
6007                                    int nRead = instream.read(buffer, 0, toRead);
6008                                    if (nRead >= 0) mBytes += nRead;
6009                                    if (nRead <= 0) break;
6010                                    toCopy -= nRead;
6011
6012                                    // send it to the output pipe as long as things
6013                                    // are still good
6014                                    if (pipeOkay) {
6015                                        try {
6016                                            pipe.write(buffer, 0, nRead);
6017                                        } catch (IOException e) {
6018                                            Slog.e(TAG, "Failed to write to restore pipe", e);
6019                                            pipeOkay = false;
6020                                        }
6021                                    }
6022                                }
6023
6024                                // done sending that file!  Now we just need to consume
6025                                // the delta from info.size to the end of block.
6026                                skipTarPadding(info.size, instream);
6027
6028                                // and now that we've sent it all, wait for the remote
6029                                // side to acknowledge receipt
6030                                agentSuccess = waitUntilOperationComplete(token);
6031                            }
6032
6033                            // okay, if the remote end failed at any point, deal with
6034                            // it by ignoring the rest of the restore on it
6035                            if (!agentSuccess) {
6036                                mBackupHandler.removeMessages(MSG_TIMEOUT);
6037                                tearDownPipes();
6038                                tearDownAgent(mTargetApp);
6039                                mAgent = null;
6040                                mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
6041                            }
6042                        }
6043
6044                        // Problems setting up the agent communication, or an already-
6045                        // ignored package: skip to the next tar stream entry by
6046                        // reading and discarding this file.
6047                        if (!okay) {
6048                            if (DEBUG) Slog.d(TAG, "[discarding file content]");
6049                            long bytesToConsume = (info.size + 511) & ~511;
6050                            while (bytesToConsume > 0) {
6051                                int toRead = (bytesToConsume > buffer.length)
6052                                ? buffer.length : (int)bytesToConsume;
6053                                long nRead = instream.read(buffer, 0, toRead);
6054                                if (nRead >= 0) mBytes += nRead;
6055                                if (nRead <= 0) break;
6056                                bytesToConsume -= nRead;
6057                            }
6058                        }
6059                    }
6060                }
6061            } catch (IOException e) {
6062                if (DEBUG) Slog.w(TAG, "io exception on restore socket read", e);
6063                // treat as EOF
6064                info = null;
6065            }
6066
6067            return (info != null);
6068        }
6069
6070        void setUpPipes() throws IOException {
6071            mPipes = ParcelFileDescriptor.createPipe();
6072        }
6073
6074        void tearDownPipes() {
6075            if (mPipes != null) {
6076                try {
6077                    mPipes[0].close();
6078                    mPipes[0] = null;
6079                    mPipes[1].close();
6080                    mPipes[1] = null;
6081                } catch (IOException e) {
6082                    Slog.w(TAG, "Couldn't close agent pipes", e);
6083                }
6084                mPipes = null;
6085            }
6086        }
6087
6088        void tearDownAgent(ApplicationInfo app) {
6089            if (mAgent != null) {
6090                try {
6091                    // unbind and tidy up even on timeout or failure, just in case
6092                    mActivityManager.unbindBackupAgent(app);
6093
6094                    // The agent was running with a stub Application object, so shut it down.
6095                    // !!! We hardcode the confirmation UI's package name here rather than use a
6096                    //     manifest flag!  TODO something less direct.
6097                    if (app.uid != Process.SYSTEM_UID
6098                            && !app.packageName.equals("com.android.backupconfirm")) {
6099                        if (DEBUG) Slog.d(TAG, "Killing host process");
6100                        mActivityManager.killApplicationProcess(app.processName, app.uid);
6101                    } else {
6102                        if (DEBUG) Slog.d(TAG, "Not killing after full restore");
6103                    }
6104                } catch (RemoteException e) {
6105                    Slog.d(TAG, "Lost app trying to shut down");
6106                }
6107                mAgent = null;
6108            }
6109        }
6110
6111        class RestoreInstallObserver extends IPackageInstallObserver.Stub {
6112            final AtomicBoolean mDone = new AtomicBoolean();
6113            String mPackageName;
6114            int mResult;
6115
6116            public void reset() {
6117                synchronized (mDone) {
6118                    mDone.set(false);
6119                }
6120            }
6121
6122            public void waitForCompletion() {
6123                synchronized (mDone) {
6124                    while (mDone.get() == false) {
6125                        try {
6126                            mDone.wait();
6127                        } catch (InterruptedException e) { }
6128                    }
6129                }
6130            }
6131
6132            int getResult() {
6133                return mResult;
6134            }
6135
6136            @Override
6137            public void packageInstalled(String packageName, int returnCode)
6138                    throws RemoteException {
6139                synchronized (mDone) {
6140                    mResult = returnCode;
6141                    mPackageName = packageName;
6142                    mDone.set(true);
6143                    mDone.notifyAll();
6144                }
6145            }
6146        }
6147
6148        class RestoreDeleteObserver extends IPackageDeleteObserver.Stub {
6149            final AtomicBoolean mDone = new AtomicBoolean();
6150            int mResult;
6151
6152            public void reset() {
6153                synchronized (mDone) {
6154                    mDone.set(false);
6155                }
6156            }
6157
6158            public void waitForCompletion() {
6159                synchronized (mDone) {
6160                    while (mDone.get() == false) {
6161                        try {
6162                            mDone.wait();
6163                        } catch (InterruptedException e) { }
6164                    }
6165                }
6166            }
6167
6168            @Override
6169            public void packageDeleted(String packageName, int returnCode) throws RemoteException {
6170                synchronized (mDone) {
6171                    mResult = returnCode;
6172                    mDone.set(true);
6173                    mDone.notifyAll();
6174                }
6175            }
6176        }
6177
6178        final RestoreInstallObserver mInstallObserver = new RestoreInstallObserver();
6179        final RestoreDeleteObserver mDeleteObserver = new RestoreDeleteObserver();
6180
6181        boolean installApk(FileMetadata info, String installerPackage, InputStream instream) {
6182            boolean okay = true;
6183
6184            if (DEBUG) Slog.d(TAG, "Installing from backup: " + info.packageName);
6185
6186            // The file content is an .apk file.  Copy it out to a staging location and
6187            // attempt to install it.
6188            File apkFile = new File(mDataDir, info.packageName);
6189            try {
6190                FileOutputStream apkStream = new FileOutputStream(apkFile);
6191                byte[] buffer = new byte[32 * 1024];
6192                long size = info.size;
6193                while (size > 0) {
6194                    long toRead = (buffer.length < size) ? buffer.length : size;
6195                    int didRead = instream.read(buffer, 0, (int)toRead);
6196                    if (didRead >= 0) mBytes += didRead;
6197                    apkStream.write(buffer, 0, didRead);
6198                    size -= didRead;
6199                }
6200                apkStream.close();
6201
6202                // make sure the installer can read it
6203                apkFile.setReadable(true, false);
6204
6205                // Now install it
6206                Uri packageUri = Uri.fromFile(apkFile);
6207                mInstallObserver.reset();
6208                mPackageManager.installPackage(packageUri, mInstallObserver,
6209                        PackageManager.INSTALL_REPLACE_EXISTING | PackageManager.INSTALL_FROM_ADB,
6210                        installerPackage);
6211                mInstallObserver.waitForCompletion();
6212
6213                if (mInstallObserver.getResult() != PackageManager.INSTALL_SUCCEEDED) {
6214                    // The only time we continue to accept install of data even if the
6215                    // apk install failed is if we had already determined that we could
6216                    // accept the data regardless.
6217                    if (mPackagePolicies.get(info.packageName) != RestorePolicy.ACCEPT) {
6218                        okay = false;
6219                    }
6220                } else {
6221                    // Okay, the install succeeded.  Make sure it was the right app.
6222                    boolean uninstall = false;
6223                    if (!mInstallObserver.mPackageName.equals(info.packageName)) {
6224                        Slog.w(TAG, "Restore stream claimed to include apk for "
6225                                + info.packageName + " but apk was really "
6226                                + mInstallObserver.mPackageName);
6227                        // delete the package we just put in place; it might be fraudulent
6228                        okay = false;
6229                        uninstall = true;
6230                    } else {
6231                        try {
6232                            PackageInfo pkg = mPackageManager.getPackageInfo(info.packageName,
6233                                    PackageManager.GET_SIGNATURES);
6234                            if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) {
6235                                Slog.w(TAG, "Restore stream contains apk of package "
6236                                        + info.packageName + " but it disallows backup/restore");
6237                                okay = false;
6238                            } else {
6239                                // So far so good -- do the signatures match the manifest?
6240                                Signature[] sigs = mManifestSignatures.get(info.packageName);
6241                                if (signaturesMatch(sigs, pkg)) {
6242                                    // If this is a system-uid app without a declared backup agent,
6243                                    // don't restore any of the file data.
6244                                    if ((pkg.applicationInfo.uid < Process.FIRST_APPLICATION_UID)
6245                                            && (pkg.applicationInfo.backupAgentName == null)) {
6246                                        Slog.w(TAG, "Installed app " + info.packageName
6247                                                + " has restricted uid and no agent");
6248                                        okay = false;
6249                                    }
6250                                } else {
6251                                    Slog.w(TAG, "Installed app " + info.packageName
6252                                            + " signatures do not match restore manifest");
6253                                    okay = false;
6254                                    uninstall = true;
6255                                }
6256                            }
6257                        } catch (NameNotFoundException e) {
6258                            Slog.w(TAG, "Install of package " + info.packageName
6259                                    + " succeeded but now not found");
6260                            okay = false;
6261                        }
6262                    }
6263
6264                    // If we're not okay at this point, we need to delete the package
6265                    // that we just installed.
6266                    if (uninstall) {
6267                        mDeleteObserver.reset();
6268                        mPackageManager.deletePackage(mInstallObserver.mPackageName,
6269                                mDeleteObserver, 0);
6270                        mDeleteObserver.waitForCompletion();
6271                    }
6272                }
6273            } catch (IOException e) {
6274                Slog.e(TAG, "Unable to transcribe restored apk for install");
6275                okay = false;
6276            } finally {
6277                apkFile.delete();
6278            }
6279
6280            return okay;
6281        }
6282
6283        // Given an actual file content size, consume the post-content padding mandated
6284        // by the tar format.
6285        void skipTarPadding(long size, InputStream instream) throws IOException {
6286            long partial = (size + 512) % 512;
6287            if (partial > 0) {
6288                final int needed = 512 - (int)partial;
6289                byte[] buffer = new byte[needed];
6290                if (readExactly(instream, buffer, 0, needed) == needed) {
6291                    mBytes += needed;
6292                } else throw new IOException("Unexpected EOF in padding");
6293            }
6294        }
6295
6296        // Read a widget metadata file, returning the restored blob
6297        void readMetadata(FileMetadata info, InputStream instream) throws IOException {
6298            // Fail on suspiciously large widget dump files
6299            if (info.size > 64 * 1024) {
6300                throw new IOException("Metadata too big; corrupt? size=" + info.size);
6301            }
6302
6303            byte[] buffer = new byte[(int) info.size];
6304            if (readExactly(instream, buffer, 0, (int)info.size) == info.size) {
6305                mBytes += info.size;
6306            } else throw new IOException("Unexpected EOF in widget data");
6307
6308            String[] str = new String[1];
6309            int offset = extractLine(buffer, 0, str);
6310            int version = Integer.parseInt(str[0]);
6311            if (version == BACKUP_MANIFEST_VERSION) {
6312                offset = extractLine(buffer, offset, str);
6313                final String pkg = str[0];
6314                if (info.packageName.equals(pkg)) {
6315                    // Data checks out -- the rest of the buffer is a concatenation of
6316                    // binary blobs as described in the comment at writeAppWidgetData()
6317                    ByteArrayInputStream bin = new ByteArrayInputStream(buffer,
6318                            offset, buffer.length - offset);
6319                    DataInputStream in = new DataInputStream(bin);
6320                    while (bin.available() > 0) {
6321                        int token = in.readInt();
6322                        int size = in.readInt();
6323                        if (size > 64 * 1024) {
6324                            throw new IOException("Datum "
6325                                    + Integer.toHexString(token)
6326                                    + " too big; corrupt? size=" + info.size);
6327                        }
6328                        switch (token) {
6329                            case BACKUP_WIDGET_METADATA_TOKEN:
6330                            {
6331                                if (MORE_DEBUG) {
6332                                    Slog.i(TAG, "Got widget metadata for " + info.packageName);
6333                                }
6334                                mWidgetData = new byte[size];
6335                                in.read(mWidgetData);
6336                                break;
6337                            }
6338                            default:
6339                            {
6340                                if (DEBUG) {
6341                                    Slog.i(TAG, "Ignoring metadata blob "
6342                                            + Integer.toHexString(token)
6343                                            + " for " + info.packageName);
6344                                }
6345                                in.skipBytes(size);
6346                                break;
6347                            }
6348                        }
6349                    }
6350                } else {
6351                    Slog.w(TAG, "Metadata mismatch: package " + info.packageName
6352                            + " but widget data for " + pkg);
6353                }
6354            } else {
6355                Slog.w(TAG, "Unsupported metadata version " + version);
6356            }
6357        }
6358
6359        // Returns a policy constant; takes a buffer arg to reduce memory churn
6360        RestorePolicy readAppManifest(FileMetadata info, InputStream instream)
6361                throws IOException {
6362            // Fail on suspiciously large manifest files
6363            if (info.size > 64 * 1024) {
6364                throw new IOException("Restore manifest too big; corrupt? size=" + info.size);
6365            }
6366
6367            byte[] buffer = new byte[(int) info.size];
6368            if (readExactly(instream, buffer, 0, (int)info.size) == info.size) {
6369                mBytes += info.size;
6370            } else throw new IOException("Unexpected EOF in manifest");
6371
6372            RestorePolicy policy = RestorePolicy.IGNORE;
6373            String[] str = new String[1];
6374            int offset = 0;
6375
6376            try {
6377                offset = extractLine(buffer, offset, str);
6378                int version = Integer.parseInt(str[0]);
6379                if (version == BACKUP_MANIFEST_VERSION) {
6380                    offset = extractLine(buffer, offset, str);
6381                    String manifestPackage = str[0];
6382                    // TODO: handle <original-package>
6383                    if (manifestPackage.equals(info.packageName)) {
6384                        offset = extractLine(buffer, offset, str);
6385                        version = Integer.parseInt(str[0]);  // app version
6386                        offset = extractLine(buffer, offset, str);
6387                        int platformVersion = Integer.parseInt(str[0]);
6388                        offset = extractLine(buffer, offset, str);
6389                        info.installerPackageName = (str[0].length() > 0) ? str[0] : null;
6390                        offset = extractLine(buffer, offset, str);
6391                        boolean hasApk = str[0].equals("1");
6392                        offset = extractLine(buffer, offset, str);
6393                        int numSigs = Integer.parseInt(str[0]);
6394                        if (numSigs > 0) {
6395                            Signature[] sigs = new Signature[numSigs];
6396                            for (int i = 0; i < numSigs; i++) {
6397                                offset = extractLine(buffer, offset, str);
6398                                sigs[i] = new Signature(str[0]);
6399                            }
6400                            mManifestSignatures.put(info.packageName, sigs);
6401
6402                            // Okay, got the manifest info we need...
6403                            try {
6404                                PackageInfo pkgInfo = mPackageManager.getPackageInfo(
6405                                        info.packageName, PackageManager.GET_SIGNATURES);
6406                                // Fall through to IGNORE if the app explicitly disallows backup
6407                                final int flags = pkgInfo.applicationInfo.flags;
6408                                if ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0) {
6409                                    // Restore system-uid-space packages only if they have
6410                                    // defined a custom backup agent
6411                                    if ((pkgInfo.applicationInfo.uid >= Process.FIRST_APPLICATION_UID)
6412                                            || (pkgInfo.applicationInfo.backupAgentName != null)) {
6413                                        // Verify signatures against any installed version; if they
6414                                        // don't match, then we fall though and ignore the data.  The
6415                                        // signatureMatch() method explicitly ignores the signature
6416                                        // check for packages installed on the system partition, because
6417                                        // such packages are signed with the platform cert instead of
6418                                        // the app developer's cert, so they're different on every
6419                                        // device.
6420                                        if (signaturesMatch(sigs, pkgInfo)) {
6421                                            if (pkgInfo.versionCode >= version) {
6422                                                Slog.i(TAG, "Sig + version match; taking data");
6423                                                policy = RestorePolicy.ACCEPT;
6424                                            } else {
6425                                                // The data is from a newer version of the app than
6426                                                // is presently installed.  That means we can only
6427                                                // use it if the matching apk is also supplied.
6428                                                Slog.d(TAG, "Data version " + version
6429                                                        + " is newer than installed version "
6430                                                        + pkgInfo.versionCode + " - requiring apk");
6431                                                policy = RestorePolicy.ACCEPT_IF_APK;
6432                                            }
6433                                        } else {
6434                                            Slog.w(TAG, "Restore manifest signatures do not match "
6435                                                    + "installed application for " + info.packageName);
6436                                        }
6437                                    } else {
6438                                        Slog.w(TAG, "Package " + info.packageName
6439                                                + " is system level with no agent");
6440                                    }
6441                                } else {
6442                                    if (DEBUG) Slog.i(TAG, "Restore manifest from "
6443                                            + info.packageName + " but allowBackup=false");
6444                                }
6445                            } catch (NameNotFoundException e) {
6446                                // Okay, the target app isn't installed.  We can process
6447                                // the restore properly only if the dataset provides the
6448                                // apk file and we can successfully install it.
6449                                if (DEBUG) Slog.i(TAG, "Package " + info.packageName
6450                                        + " not installed; requiring apk in dataset");
6451                                policy = RestorePolicy.ACCEPT_IF_APK;
6452                            }
6453
6454                            if (policy == RestorePolicy.ACCEPT_IF_APK && !hasApk) {
6455                                Slog.i(TAG, "Cannot restore package " + info.packageName
6456                                        + " without the matching .apk");
6457                            }
6458                        } else {
6459                            Slog.i(TAG, "Missing signature on backed-up package "
6460                                    + info.packageName);
6461                        }
6462                    } else {
6463                        Slog.i(TAG, "Expected package " + info.packageName
6464                                + " but restore manifest claims " + manifestPackage);
6465                    }
6466                } else {
6467                    Slog.i(TAG, "Unknown restore manifest version " + version
6468                            + " for package " + info.packageName);
6469                }
6470            } catch (NumberFormatException e) {
6471                Slog.w(TAG, "Corrupt restore manifest for package " + info.packageName);
6472            } catch (IllegalArgumentException e) {
6473                Slog.w(TAG, e.getMessage());
6474            }
6475
6476            return policy;
6477        }
6478
6479        // Builds a line from a byte buffer starting at 'offset', and returns
6480        // the index of the next unconsumed data in the buffer.
6481        int extractLine(byte[] buffer, int offset, String[] outStr) throws IOException {
6482            final int end = buffer.length;
6483            if (offset >= end) throw new IOException("Incomplete data");
6484
6485            int pos;
6486            for (pos = offset; pos < end; pos++) {
6487                byte c = buffer[pos];
6488                // at LF we declare end of line, and return the next char as the
6489                // starting point for the next time through
6490                if (c == '\n') {
6491                    break;
6492                }
6493            }
6494            outStr[0] = new String(buffer, offset, pos - offset);
6495            pos++;  // may be pointing an extra byte past the end but that's okay
6496            return pos;
6497        }
6498
6499        void dumpFileMetadata(FileMetadata info) {
6500            if (DEBUG) {
6501                StringBuilder b = new StringBuilder(128);
6502
6503                // mode string
6504                b.append((info.type == BackupAgent.TYPE_DIRECTORY) ? 'd' : '-');
6505                b.append(((info.mode & 0400) != 0) ? 'r' : '-');
6506                b.append(((info.mode & 0200) != 0) ? 'w' : '-');
6507                b.append(((info.mode & 0100) != 0) ? 'x' : '-');
6508                b.append(((info.mode & 0040) != 0) ? 'r' : '-');
6509                b.append(((info.mode & 0020) != 0) ? 'w' : '-');
6510                b.append(((info.mode & 0010) != 0) ? 'x' : '-');
6511                b.append(((info.mode & 0004) != 0) ? 'r' : '-');
6512                b.append(((info.mode & 0002) != 0) ? 'w' : '-');
6513                b.append(((info.mode & 0001) != 0) ? 'x' : '-');
6514                b.append(String.format(" %9d ", info.size));
6515
6516                Date stamp = new Date(info.mtime);
6517                b.append(new SimpleDateFormat("MMM dd HH:mm:ss ").format(stamp));
6518
6519                b.append(info.packageName);
6520                b.append(" :: ");
6521                b.append(info.domain);
6522                b.append(" :: ");
6523                b.append(info.path);
6524
6525                Slog.i(TAG, b.toString());
6526            }
6527        }
6528        // Consume a tar file header block [sequence] and accumulate the relevant metadata
6529        FileMetadata readTarHeaders(InputStream instream) throws IOException {
6530            byte[] block = new byte[512];
6531            FileMetadata info = null;
6532
6533            boolean gotHeader = readTarHeader(instream, block);
6534            if (gotHeader) {
6535                try {
6536                    // okay, presume we're okay, and extract the various metadata
6537                    info = new FileMetadata();
6538                    info.size = extractRadix(block, 124, 12, 8);
6539                    info.mtime = extractRadix(block, 136, 12, 8);
6540                    info.mode = extractRadix(block, 100, 8, 8);
6541
6542                    info.path = extractString(block, 345, 155); // prefix
6543                    String path = extractString(block, 0, 100);
6544                    if (path.length() > 0) {
6545                        if (info.path.length() > 0) info.path += '/';
6546                        info.path += path;
6547                    }
6548
6549                    // tar link indicator field: 1 byte at offset 156 in the header.
6550                    int typeChar = block[156];
6551                    if (typeChar == 'x') {
6552                        // pax extended header, so we need to read that
6553                        gotHeader = readPaxExtendedHeader(instream, info);
6554                        if (gotHeader) {
6555                            // and after a pax extended header comes another real header -- read
6556                            // that to find the real file type
6557                            gotHeader = readTarHeader(instream, block);
6558                        }
6559                        if (!gotHeader) throw new IOException("Bad or missing pax header");
6560
6561                        typeChar = block[156];
6562                    }
6563
6564                    switch (typeChar) {
6565                        case '0': info.type = BackupAgent.TYPE_FILE; break;
6566                        case '5': {
6567                            info.type = BackupAgent.TYPE_DIRECTORY;
6568                            if (info.size != 0) {
6569                                Slog.w(TAG, "Directory entry with nonzero size in header");
6570                                info.size = 0;
6571                            }
6572                            break;
6573                        }
6574                        case 0: {
6575                            // presume EOF
6576                            if (DEBUG) Slog.w(TAG, "Saw type=0 in tar header block, info=" + info);
6577                            return null;
6578                        }
6579                        default: {
6580                            Slog.e(TAG, "Unknown tar entity type: " + typeChar);
6581                            throw new IOException("Unknown entity type " + typeChar);
6582                        }
6583                    }
6584
6585                    // Parse out the path
6586                    //
6587                    // first: apps/shared/unrecognized
6588                    if (FullBackup.SHARED_PREFIX.regionMatches(0,
6589                            info.path, 0, FullBackup.SHARED_PREFIX.length())) {
6590                        // File in shared storage.  !!! TODO: implement this.
6591                        info.path = info.path.substring(FullBackup.SHARED_PREFIX.length());
6592                        info.packageName = SHARED_BACKUP_AGENT_PACKAGE;
6593                        info.domain = FullBackup.SHARED_STORAGE_TOKEN;
6594                        if (DEBUG) Slog.i(TAG, "File in shared storage: " + info.path);
6595                    } else if (FullBackup.APPS_PREFIX.regionMatches(0,
6596                            info.path, 0, FullBackup.APPS_PREFIX.length())) {
6597                        // App content!  Parse out the package name and domain
6598
6599                        // strip the apps/ prefix
6600                        info.path = info.path.substring(FullBackup.APPS_PREFIX.length());
6601
6602                        // extract the package name
6603                        int slash = info.path.indexOf('/');
6604                        if (slash < 0) throw new IOException("Illegal semantic path in " + info.path);
6605                        info.packageName = info.path.substring(0, slash);
6606                        info.path = info.path.substring(slash+1);
6607
6608                        // if it's a manifest or metadata payload we're done, otherwise parse
6609                        // out the domain into which the file will be restored
6610                        if (!info.path.equals(BACKUP_MANIFEST_FILENAME)
6611                                && !info.path.equals(BACKUP_METADATA_FILENAME)) {
6612                            slash = info.path.indexOf('/');
6613                            if (slash < 0) throw new IOException("Illegal semantic path in non-manifest " + info.path);
6614                            info.domain = info.path.substring(0, slash);
6615                            info.path = info.path.substring(slash + 1);
6616                        }
6617                    }
6618                } catch (IOException e) {
6619                    if (DEBUG) {
6620                        Slog.e(TAG, "Parse error in header: " + e.getMessage());
6621                        HEXLOG(block);
6622                    }
6623                    throw e;
6624                }
6625            }
6626            return info;
6627        }
6628
6629        private void HEXLOG(byte[] block) {
6630            int offset = 0;
6631            int todo = block.length;
6632            StringBuilder buf = new StringBuilder(64);
6633            while (todo > 0) {
6634                buf.append(String.format("%04x   ", offset));
6635                int numThisLine = (todo > 16) ? 16 : todo;
6636                for (int i = 0; i < numThisLine; i++) {
6637                    buf.append(String.format("%02x ", block[offset+i]));
6638                }
6639                Slog.i("hexdump", buf.toString());
6640                buf.setLength(0);
6641                todo -= numThisLine;
6642                offset += numThisLine;
6643            }
6644        }
6645
6646        // Read exactly the given number of bytes into a buffer at the stated offset.
6647        // Returns false if EOF is encountered before the requested number of bytes
6648        // could be read.
6649        int readExactly(InputStream in, byte[] buffer, int offset, int size)
6650                throws IOException {
6651            if (size <= 0) throw new IllegalArgumentException("size must be > 0");
6652
6653            int soFar = 0;
6654            while (soFar < size) {
6655                int nRead = in.read(buffer, offset + soFar, size - soFar);
6656                if (nRead <= 0) {
6657                    if (MORE_DEBUG) Slog.w(TAG, "- wanted exactly " + size + " but got only " + soFar);
6658                    break;
6659                }
6660                soFar += nRead;
6661            }
6662            return soFar;
6663        }
6664
6665        boolean readTarHeader(InputStream instream, byte[] block) throws IOException {
6666            final int got = readExactly(instream, block, 0, 512);
6667            if (got == 0) return false;     // Clean EOF
6668            if (got < 512) throw new IOException("Unable to read full block header");
6669            mBytes += 512;
6670            return true;
6671        }
6672
6673        // overwrites 'info' fields based on the pax extended header
6674        boolean readPaxExtendedHeader(InputStream instream, FileMetadata info)
6675                throws IOException {
6676            // We should never see a pax extended header larger than this
6677            if (info.size > 32*1024) {
6678                Slog.w(TAG, "Suspiciously large pax header size " + info.size
6679                        + " - aborting");
6680                throw new IOException("Sanity failure: pax header size " + info.size);
6681            }
6682
6683            // read whole blocks, not just the content size
6684            int numBlocks = (int)((info.size + 511) >> 9);
6685            byte[] data = new byte[numBlocks * 512];
6686            if (readExactly(instream, data, 0, data.length) < data.length) {
6687                throw new IOException("Unable to read full pax header");
6688            }
6689            mBytes += data.length;
6690
6691            final int contentSize = (int) info.size;
6692            int offset = 0;
6693            do {
6694                // extract the line at 'offset'
6695                int eol = offset+1;
6696                while (eol < contentSize && data[eol] != ' ') eol++;
6697                if (eol >= contentSize) {
6698                    // error: we just hit EOD looking for the end of the size field
6699                    throw new IOException("Invalid pax data");
6700                }
6701                // eol points to the space between the count and the key
6702                int linelen = (int) extractRadix(data, offset, eol - offset, 10);
6703                int key = eol + 1;  // start of key=value
6704                eol = offset + linelen - 1; // trailing LF
6705                int value;
6706                for (value = key+1; data[value] != '=' && value <= eol; value++);
6707                if (value > eol) {
6708                    throw new IOException("Invalid pax declaration");
6709                }
6710
6711                // pax requires that key/value strings be in UTF-8
6712                String keyStr = new String(data, key, value-key, "UTF-8");
6713                // -1 to strip the trailing LF
6714                String valStr = new String(data, value+1, eol-value-1, "UTF-8");
6715
6716                if ("path".equals(keyStr)) {
6717                    info.path = valStr;
6718                } else if ("size".equals(keyStr)) {
6719                    info.size = Long.parseLong(valStr);
6720                } else {
6721                    if (DEBUG) Slog.i(TAG, "Unhandled pax key: " + key);
6722                }
6723
6724                offset += linelen;
6725            } while (offset < contentSize);
6726
6727            return true;
6728        }
6729
6730        long extractRadix(byte[] data, int offset, int maxChars, int radix)
6731                throws IOException {
6732            long value = 0;
6733            final int end = offset + maxChars;
6734            for (int i = offset; i < end; i++) {
6735                final byte b = data[i];
6736                // Numeric fields in tar can terminate with either NUL or SPC
6737                if (b == 0 || b == ' ') break;
6738                if (b < '0' || b > ('0' + radix - 1)) {
6739                    throw new IOException("Invalid number in header: '" + (char)b + "' for radix " + radix);
6740                }
6741                value = radix * value + (b - '0');
6742            }
6743            return value;
6744        }
6745
6746        String extractString(byte[] data, int offset, int maxChars) throws IOException {
6747            final int end = offset + maxChars;
6748            int eos = offset;
6749            // tar string fields terminate early with a NUL
6750            while (eos < end && data[eos] != 0) eos++;
6751            return new String(data, offset, eos-offset, "US-ASCII");
6752        }
6753
6754        void sendStartRestore() {
6755            if (mObserver != null) {
6756                try {
6757                    mObserver.onStartRestore();
6758                } catch (RemoteException e) {
6759                    Slog.w(TAG, "full restore observer went away: startRestore");
6760                    mObserver = null;
6761                }
6762            }
6763        }
6764
6765        void sendOnRestorePackage(String name) {
6766            if (mObserver != null) {
6767                try {
6768                    // TODO: use a more user-friendly name string
6769                    mObserver.onRestorePackage(name);
6770                } catch (RemoteException e) {
6771                    Slog.w(TAG, "full restore observer went away: restorePackage");
6772                    mObserver = null;
6773                }
6774            }
6775        }
6776
6777        void sendEndRestore() {
6778            if (mObserver != null) {
6779                try {
6780                    mObserver.onEndRestore();
6781                } catch (RemoteException e) {
6782                    Slog.w(TAG, "full restore observer went away: endRestore");
6783                    mObserver = null;
6784                }
6785            }
6786        }
6787    }
6788
6789    // ----- Restore handling -----
6790
6791    // new style: we only store the SHA-1 hashes of each sig, not the full block
6792    static boolean signaturesMatch(ArrayList<byte[]> storedSigHashes, PackageInfo target) {
6793        if (target == null) {
6794            return false;
6795        }
6796
6797        // If the target resides on the system partition, we allow it to restore
6798        // data from the like-named package in a restore set even if the signatures
6799        // do not match.  (Unlike general applications, those flashed to the system
6800        // partition will be signed with the device's platform certificate, so on
6801        // different phones the same system app will have different signatures.)
6802        if ((target.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
6803            if (DEBUG) Slog.v(TAG, "System app " + target.packageName + " - skipping sig check");
6804            return true;
6805        }
6806
6807        // Allow unsigned apps, but not signed on one device and unsigned on the other
6808        // !!! TODO: is this the right policy?
6809        Signature[] deviceSigs = target.signatures;
6810        if (MORE_DEBUG) Slog.v(TAG, "signaturesMatch(): stored=" + storedSigHashes
6811                + " device=" + deviceSigs);
6812        if ((storedSigHashes == null || storedSigHashes.size() == 0)
6813                && (deviceSigs == null || deviceSigs.length == 0)) {
6814            return true;
6815        }
6816        if (storedSigHashes == null || deviceSigs == null) {
6817            return false;
6818        }
6819
6820        // !!! TODO: this demands that every stored signature match one
6821        // that is present on device, and does not demand the converse.
6822        // Is this this right policy?
6823        final int nStored = storedSigHashes.size();
6824        final int nDevice = deviceSigs.length;
6825
6826        // hash each on-device signature
6827        ArrayList<byte[]> deviceHashes = new ArrayList<byte[]>(nDevice);
6828        for (int i = 0; i < nDevice; i++) {
6829            deviceHashes.add(hashSignature(deviceSigs[i]));
6830        }
6831
6832        // now ensure that each stored sig (hash) matches an on-device sig (hash)
6833        for (int n = 0; n < nStored; n++) {
6834            boolean match = false;
6835            final byte[] storedHash = storedSigHashes.get(n);
6836            for (int i = 0; i < nDevice; i++) {
6837                if (Arrays.equals(storedHash, deviceHashes.get(i))) {
6838                    match = true;
6839                    break;
6840                }
6841            }
6842            // match is false when no on-device sig matched one of the stored ones
6843            if (!match) {
6844                return false;
6845            }
6846        }
6847
6848        return true;
6849    }
6850
6851    static byte[] hashSignature(Signature sig) {
6852        try {
6853            MessageDigest digest = MessageDigest.getInstance("SHA-256");
6854            digest.update(sig.toByteArray());
6855            return digest.digest();
6856        } catch (NoSuchAlgorithmException e) {
6857            Slog.w(TAG, "No SHA-256 algorithm found!");
6858        }
6859        return null;
6860    }
6861
6862    // Old style: directly match the stored vs on device signature blocks
6863    static boolean signaturesMatch(Signature[] storedSigs, PackageInfo target) {
6864        if (target == null) {
6865            return false;
6866        }
6867
6868        // If the target resides on the system partition, we allow it to restore
6869        // data from the like-named package in a restore set even if the signatures
6870        // do not match.  (Unlike general applications, those flashed to the system
6871        // partition will be signed with the device's platform certificate, so on
6872        // different phones the same system app will have different signatures.)
6873        if ((target.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
6874            if (DEBUG) Slog.v(TAG, "System app " + target.packageName + " - skipping sig check");
6875            return true;
6876        }
6877
6878        // Allow unsigned apps, but not signed on one device and unsigned on the other
6879        // !!! TODO: is this the right policy?
6880        Signature[] deviceSigs = target.signatures;
6881        if (MORE_DEBUG) Slog.v(TAG, "signaturesMatch(): stored=" + storedSigs
6882                + " device=" + deviceSigs);
6883        if ((storedSigs == null || storedSigs.length == 0)
6884                && (deviceSigs == null || deviceSigs.length == 0)) {
6885            return true;
6886        }
6887        if (storedSigs == null || deviceSigs == null) {
6888            return false;
6889        }
6890
6891        // !!! TODO: this demands that every stored signature match one
6892        // that is present on device, and does not demand the converse.
6893        // Is this this right policy?
6894        int nStored = storedSigs.length;
6895        int nDevice = deviceSigs.length;
6896
6897        for (int i=0; i < nStored; i++) {
6898            boolean match = false;
6899            for (int j=0; j < nDevice; j++) {
6900                if (storedSigs[i].equals(deviceSigs[j])) {
6901                    match = true;
6902                    break;
6903                }
6904            }
6905            if (!match) {
6906                return false;
6907            }
6908        }
6909        return true;
6910    }
6911
6912    // Used by both incremental and full restore
6913    void restoreWidgetData(String packageName, byte[] widgetData) {
6914        // Apply the restored widget state and generate the ID update for the app
6915        AppWidgetBackupBridge.restoreWidgetState(packageName, widgetData, UserHandle.USER_OWNER);
6916    }
6917
6918    // *****************************
6919    // NEW UNIFIED RESTORE IMPLEMENTATION
6920    // *****************************
6921
6922    // states of the unified-restore state machine
6923    enum UnifiedRestoreState {
6924        INITIAL,
6925        RUNNING_QUEUE,
6926        RESTORE_KEYVALUE,
6927        RESTORE_FULL,
6928        RESTORE_FINISHED,
6929        FINAL
6930    }
6931
6932    class PerformUnifiedRestoreTask implements BackupRestoreTask {
6933        // Transport we're working with to do the restore
6934        private IBackupTransport mTransport;
6935
6936        // Where per-transport saved state goes
6937        File mStateDir;
6938
6939        // Restore observer; may be null
6940        private IRestoreObserver mObserver;
6941
6942        // Token identifying the dataset to the transport
6943        private long mToken;
6944
6945        // When this is a restore-during-install, this is the token identifying the
6946        // operation to the Package Manager, and we must ensure that we let it know
6947        // when we're finished.
6948        private int mPmToken;
6949
6950        // Is this a whole-system restore, i.e. are we establishing a new ancestral
6951        // dataset to base future restore-at-install operations from?
6952        private boolean mIsSystemRestore;
6953
6954        // If this is a single-package restore, what package are we interested in?
6955        private PackageInfo mTargetPackage;
6956
6957        // In all cases, the calculated list of packages that we are trying to restore
6958        private List<PackageInfo> mAcceptSet;
6959
6960        // Our bookkeeping about the ancestral dataset
6961        private PackageManagerBackupAgent mPmAgent;
6962
6963        // Currently-bound backup agent for restore + restoreFinished purposes
6964        private IBackupAgent mAgent;
6965
6966        // What sort of restore we're doing now
6967        private RestoreDescription mRestoreDescription;
6968
6969        // The package we're currently restoring
6970        private PackageInfo mCurrentPackage;
6971
6972        // Widget-related data handled as part of this restore operation
6973        private byte[] mWidgetData;
6974
6975        // Number of apps restored in this pass
6976        private int mCount;
6977
6978        // When did we start?
6979        private long mStartRealtime;
6980
6981        // State machine progress
6982        private UnifiedRestoreState mState;
6983
6984        // How are things going?
6985        private int mStatus;
6986
6987        // Done?
6988        private boolean mFinished;
6989
6990        // Key/value: bookkeeping about staged data and files for agent access
6991        private File mBackupDataName;
6992        private File mStageName;
6993        private File mSavedStateName;
6994        private File mNewStateName;
6995        ParcelFileDescriptor mBackupData;
6996        ParcelFileDescriptor mNewState;
6997
6998        // Invariant: mWakelock is already held, and this task is responsible for
6999        // releasing it at the end of the restore operation.
7000        PerformUnifiedRestoreTask(IBackupTransport transport, IRestoreObserver observer,
7001                long restoreSetToken, PackageInfo targetPackage, int pmToken,
7002                boolean isFullSystemRestore, String[] filterSet) {
7003            mState = UnifiedRestoreState.INITIAL;
7004            mStartRealtime = SystemClock.elapsedRealtime();
7005
7006            mTransport = transport;
7007            mObserver = observer;
7008            mToken = restoreSetToken;
7009            mPmToken = pmToken;
7010            mTargetPackage = targetPackage;
7011            mIsSystemRestore = isFullSystemRestore;
7012            mFinished = false;
7013
7014            if (targetPackage != null) {
7015                // Single package restore
7016                mAcceptSet = new ArrayList<PackageInfo>();
7017                mAcceptSet.add(targetPackage);
7018            } else {
7019                // Everything possible, or a target set
7020                if (filterSet == null) {
7021                    // We want everything and a pony
7022                    List<PackageInfo> apps =
7023                            PackageManagerBackupAgent.getStorableApplications(mPackageManager);
7024                    filterSet = packagesToNames(apps);
7025                    if (DEBUG) {
7026                        Slog.i(TAG, "Full restore; asking for " + filterSet.length + " apps");
7027                    }
7028                }
7029
7030                mAcceptSet = new ArrayList<PackageInfo>(filterSet.length);
7031
7032                // Pro tem, we insist on moving the settings provider package to last place.
7033                // Keep track of whether it's in the list, and bump it down if so.  We also
7034                // want to do the system package itself first if it's called for.
7035                boolean hasSystem = false;
7036                boolean hasSettings = false;
7037                for (int i = 0; i < filterSet.length; i++) {
7038                    try {
7039                        PackageInfo info = mPackageManager.getPackageInfo(filterSet[i], 0);
7040                        if ("android".equals(info.packageName)) {
7041                            hasSystem = true;
7042                            continue;
7043                        }
7044                        if (SETTINGS_PACKAGE.equals(info.packageName)) {
7045                            hasSettings = true;
7046                            continue;
7047                        }
7048
7049                        if (appIsEligibleForBackup(info.applicationInfo)) {
7050                            mAcceptSet.add(info);
7051                        }
7052                    } catch (NameNotFoundException e) {
7053                        // requested package name doesn't exist; ignore it
7054                    }
7055                }
7056                if (hasSystem) {
7057                    try {
7058                        mAcceptSet.add(0, mPackageManager.getPackageInfo("android", 0));
7059                    } catch (NameNotFoundException e) {
7060                        // won't happen; we know a priori that it's valid
7061                    }
7062                }
7063                if (hasSettings) {
7064                    try {
7065                        mAcceptSet.add(mPackageManager.getPackageInfo(SETTINGS_PACKAGE, 0));
7066                    } catch (NameNotFoundException e) {
7067                        // this one is always valid too
7068                    }
7069                }
7070            }
7071
7072            if (MORE_DEBUG) {
7073                Slog.v(TAG, "Restore; accept set size is " + mAcceptSet.size());
7074                for (PackageInfo info : mAcceptSet) {
7075                    Slog.v(TAG, "   " + info.packageName);
7076                }
7077            }
7078        }
7079
7080        private String[] packagesToNames(List<PackageInfo> apps) {
7081            final int N = apps.size();
7082            String[] names = new String[N];
7083            for (int i = 0; i < N; i++) {
7084                names[i] = apps.get(i).packageName;
7085            }
7086            return names;
7087        }
7088
7089        // Execute one tick of whatever state machine the task implements
7090        @Override
7091        public void execute() {
7092            if (MORE_DEBUG) Slog.v(TAG, "*** Executing restore step " + mState);
7093            switch (mState) {
7094                case INITIAL:
7095                    startRestore();
7096                    break;
7097
7098                case RUNNING_QUEUE:
7099                    dispatchNextRestore();
7100                    break;
7101
7102                case RESTORE_KEYVALUE:
7103                    restoreKeyValue();
7104                    break;
7105
7106                case RESTORE_FULL:
7107                    restoreFull();
7108                    break;
7109
7110                case RESTORE_FINISHED:
7111                    restoreFinished();
7112                    break;
7113
7114                case FINAL:
7115                    if (!mFinished) finalizeRestore();
7116                    else {
7117                        Slog.e(TAG, "Duplicate finish");
7118                    }
7119                    mFinished = true;
7120                    break;
7121            }
7122        }
7123
7124        /*
7125         * SKETCH OF OPERATION
7126         *
7127         * create one of these PerformUnifiedRestoreTask objects, telling it which
7128         * dataset & transport to address, and then parameters within the restore
7129         * operation: single target package vs many, etc.
7130         *
7131         * 1. transport.startRestore(token, list-of-packages).  If we need @pm@  it is
7132         * always placed first and the settings provider always placed last [for now].
7133         *
7134         * 1a [if we needed @pm@ then nextRestorePackage() and restore the PMBA inline]
7135         *
7136         *   [ state change => RUNNING_QUEUE ]
7137         *
7138         * NOW ITERATE:
7139         *
7140         * { 3. t.nextRestorePackage()
7141         *   4. does the metadata for this package allow us to restore it?
7142         *      does the on-disk app permit us to restore it? [re-check allowBackup etc]
7143         *   5. is this a key/value dataset?  => key/value agent restore
7144         *       [ state change => RESTORE_KEYVALUE ]
7145         *       5a. spin up agent
7146         *       5b. t.getRestoreData() to stage it properly
7147         *       5c. call into agent to perform restore
7148         *       5d. tear down agent
7149         *       [ state change => RUNNING_QUEUE ]
7150         *
7151         *   6. else it's a stream dataset:
7152         *       [ state change => RESTORE_FULL ]
7153         *       6a. instantiate the engine for a stream restore: engine handles agent lifecycles
7154         *       6b. spin off engine runner on separate thread
7155         *       6c. ITERATE getNextFullRestoreDataChunk() and copy data to engine runner socket
7156         *       [ state change => RUNNING_QUEUE ]
7157         * }
7158         *
7159         *   [ state change => FINAL ]
7160         *
7161         * 7. t.finishRestore(), release wakelock, etc.
7162         *
7163         *
7164         */
7165
7166        // state INITIAL : set up for the restore and read the metadata if necessary
7167        private  void startRestore() {
7168            sendStartRestore(mAcceptSet.size());
7169
7170            // If we're starting a full-system restore, set up to begin widget ID remapping
7171            if (mIsSystemRestore) {
7172                AppWidgetBackupBridge.restoreStarting(UserHandle.USER_OWNER);
7173            }
7174
7175            try {
7176                String transportDir = mTransport.transportDirName();
7177                mStateDir = new File(mBaseStateDir, transportDir);
7178
7179                // Fetch the current metadata from the dataset first
7180                PackageInfo pmPackage = new PackageInfo();
7181                pmPackage.packageName = PACKAGE_MANAGER_SENTINEL;
7182                mAcceptSet.add(0, pmPackage);
7183
7184                PackageInfo[] packages = mAcceptSet.toArray(new PackageInfo[0]);
7185                mStatus = mTransport.startRestore(mToken, packages);
7186                if (mStatus != BackupTransport.TRANSPORT_OK) {
7187                    Slog.e(TAG, "Transport error " + mStatus + "; no restore possible");
7188                    mStatus = BackupTransport.TRANSPORT_ERROR;
7189                    executeNextState(UnifiedRestoreState.FINAL);
7190                    return;
7191                }
7192
7193                RestoreDescription desc = mTransport.nextRestorePackage();
7194                if (desc == null) {
7195                    Slog.e(TAG, "No restore metadata available; halting");
7196                    mStatus = BackupTransport.TRANSPORT_ERROR;
7197                    executeNextState(UnifiedRestoreState.FINAL);
7198                    return;
7199                }
7200                if (!PACKAGE_MANAGER_SENTINEL.equals(desc.getPackageName())) {
7201                    Slog.e(TAG, "Required metadata but got " + desc.getPackageName());
7202                    mStatus = BackupTransport.TRANSPORT_ERROR;
7203                    executeNextState(UnifiedRestoreState.FINAL);
7204                    return;
7205                }
7206
7207                // Pull the Package Manager metadata from the restore set first
7208                mCurrentPackage = new PackageInfo();
7209                mCurrentPackage.packageName = PACKAGE_MANAGER_SENTINEL;
7210                mPmAgent = new PackageManagerBackupAgent(mPackageManager, null);
7211                mAgent = IBackupAgent.Stub.asInterface(mPmAgent.onBind());
7212                if (MORE_DEBUG) {
7213                    Slog.v(TAG, "initiating restore for PMBA");
7214                }
7215                initiateOneRestore(mCurrentPackage, 0);
7216                // The PM agent called operationComplete() already, because our invocation
7217                // of it is process-local and therefore synchronous.  That means that the
7218                // next-state message (RUNNING_QUEUE) is already enqueued.  Only if we're
7219                // unable to proceed with running the queue do we remove that pending
7220                // message and jump straight to the FINAL state.
7221
7222                // Verify that the backup set includes metadata.  If not, we can't do
7223                // signature/version verification etc, so we simply do not proceed with
7224                // the restore operation.
7225                if (!mPmAgent.hasMetadata()) {
7226                    Slog.e(TAG, "No restore metadata available, so not restoring");
7227                    EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
7228                            PACKAGE_MANAGER_SENTINEL,
7229                            "Package manager restore metadata missing");
7230                    mStatus = BackupTransport.TRANSPORT_ERROR;
7231                    mBackupHandler.removeMessages(MSG_BACKUP_RESTORE_STEP, this);
7232                    executeNextState(UnifiedRestoreState.FINAL);
7233                    return;
7234                }
7235
7236                // Success; cache the metadata and continue as expected with the
7237                // next state already enqueued
7238
7239            } catch (RemoteException e) {
7240                // If we lost the transport at any time, halt
7241                Slog.e(TAG, "Unable to contact transport for restore");
7242                mStatus = BackupTransport.TRANSPORT_ERROR;
7243                mBackupHandler.removeMessages(MSG_BACKUP_RESTORE_STEP, this);
7244                executeNextState(UnifiedRestoreState.FINAL);
7245                return;
7246            }
7247        }
7248
7249        // state RUNNING_QUEUE : figure out what the next thing to be restored is,
7250        // and fire the appropriate next step
7251        private void dispatchNextRestore() {
7252            UnifiedRestoreState nextState = UnifiedRestoreState.FINAL;
7253            try {
7254                mRestoreDescription = mTransport.nextRestorePackage();
7255                final String pkgName = (mRestoreDescription != null)
7256                        ? mRestoreDescription.getPackageName() : null;
7257                if (pkgName == null) {
7258                    Slog.e(TAG, "Failure getting next package name");
7259                    EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
7260                    nextState = UnifiedRestoreState.FINAL;
7261                    return;
7262                } else if (mRestoreDescription == RestoreDescription.NO_MORE_PACKAGES) {
7263                    // Yay we've reached the end cleanly
7264                    if (DEBUG) {
7265                        Slog.v(TAG, "No more packages; finishing restore");
7266                    }
7267                    int millis = (int) (SystemClock.elapsedRealtime() - mStartRealtime);
7268                    EventLog.writeEvent(EventLogTags.RESTORE_SUCCESS, mCount, millis);
7269                    nextState = UnifiedRestoreState.FINAL;
7270                    return;
7271                }
7272
7273                if (DEBUG) {
7274                    Slog.i(TAG, "Next restore package: " + mRestoreDescription);
7275                }
7276                sendOnRestorePackage(pkgName);
7277
7278                Metadata metaInfo = mPmAgent.getRestoredMetadata(pkgName);
7279                if (metaInfo == null) {
7280                    Slog.e(TAG, "No metadata for " + pkgName);
7281                    EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, pkgName,
7282                            "Package metadata missing");
7283                    nextState = UnifiedRestoreState.RUNNING_QUEUE;
7284                    return;
7285                }
7286
7287                try {
7288                    mCurrentPackage = mPackageManager.getPackageInfo(
7289                            pkgName, PackageManager.GET_SIGNATURES);
7290                } catch (NameNotFoundException e) {
7291                    // Whoops, we thought we could restore this package but it
7292                    // turns out not to be present.  Skip it.
7293                    Slog.e(TAG, "Package not present: " + pkgName);
7294                    EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, pkgName,
7295                            "Package missing on device");
7296                    nextState = UnifiedRestoreState.RUNNING_QUEUE;
7297                    return;
7298                }
7299
7300                if (metaInfo.versionCode > mCurrentPackage.versionCode) {
7301                    // Data is from a "newer" version of the app than we have currently
7302                    // installed.  If the app has not declared that it is prepared to
7303                    // handle this case, we do not attempt the restore.
7304                    if ((mCurrentPackage.applicationInfo.flags
7305                            & ApplicationInfo.FLAG_RESTORE_ANY_VERSION) == 0) {
7306                        String message = "Version " + metaInfo.versionCode
7307                                + " > installed version " + mCurrentPackage.versionCode;
7308                        Slog.w(TAG, "Package " + pkgName + ": " + message);
7309                        EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
7310                                pkgName, message);
7311                        nextState = UnifiedRestoreState.RUNNING_QUEUE;
7312                        return;
7313                    } else {
7314                        if (DEBUG) Slog.v(TAG, "Version " + metaInfo.versionCode
7315                                + " > installed " + mCurrentPackage.versionCode
7316                                + " but restoreAnyVersion");
7317                    }
7318                }
7319
7320                if (DEBUG) Slog.v(TAG, "Package " + pkgName
7321                        + " restore version [" + metaInfo.versionCode
7322                        + "] is compatible with installed version ["
7323                        + mCurrentPackage.versionCode + "]");
7324
7325                // Reset per-package preconditions and fire the appropriate next state
7326                mWidgetData = null;
7327                final int type = mRestoreDescription.getDataType();
7328                if (type == RestoreDescription.TYPE_KEY_VALUE) {
7329                    nextState = UnifiedRestoreState.RESTORE_KEYVALUE;
7330                } else if (type == RestoreDescription.TYPE_FULL_STREAM) {
7331                    nextState = UnifiedRestoreState.RESTORE_FULL;
7332                } else {
7333                    // Unknown restore type; ignore this package and move on
7334                    Slog.e(TAG, "Unrecognized restore type " + type);
7335                    nextState = UnifiedRestoreState.RUNNING_QUEUE;
7336                    return;
7337                }
7338            } catch (RemoteException e) {
7339                Slog.e(TAG, "Can't get next target from transport; ending restore");
7340                EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
7341                nextState = UnifiedRestoreState.FINAL;
7342                return;
7343            } finally {
7344                executeNextState(nextState);
7345            }
7346        }
7347
7348        // state RESTORE_KEYVALUE : restore one package via key/value API set
7349        private void restoreKeyValue() {
7350            // Initiating the restore will pass responsibility for the state machine's
7351            // progress to the agent callback, so we do not always execute the
7352            // next state here.
7353            final String packageName = mCurrentPackage.packageName;
7354            // Validate some semantic requirements that apply in this way
7355            // only to the key/value restore API flow
7356            if (mCurrentPackage.applicationInfo.backupAgentName == null
7357                    || "".equals(mCurrentPackage.applicationInfo.backupAgentName)) {
7358                if (DEBUG) {
7359                    Slog.i(TAG, "Data exists for package " + packageName
7360                            + " but app has no agent; skipping");
7361                }
7362                EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
7363                        "Package has no agent");
7364                executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
7365                return;
7366            }
7367
7368            Metadata metaInfo = mPmAgent.getRestoredMetadata(packageName);
7369            if (!signaturesMatch(metaInfo.sigHashes, mCurrentPackage)) {
7370                Slog.w(TAG, "Signature mismatch restoring " + packageName);
7371                EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
7372                        "Signature mismatch");
7373                executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
7374                return;
7375            }
7376
7377            // Good to go!  Set up and bind the agent...
7378            mAgent = bindToAgentSynchronous(
7379                    mCurrentPackage.applicationInfo,
7380                    IApplicationThread.BACKUP_MODE_INCREMENTAL);
7381            if (mAgent == null) {
7382                Slog.w(TAG, "Can't find backup agent for " + packageName);
7383                EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
7384                        "Restore agent missing");
7385                executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
7386                return;
7387            }
7388
7389            // And then finally start the restore on this agent
7390            try {
7391                initiateOneRestore(mCurrentPackage, metaInfo.versionCode);
7392                ++mCount;
7393            } catch (Exception e) {
7394                Slog.e(TAG, "Error when attempting restore: " + e.toString());
7395                keyValueAgentErrorCleanup();
7396                executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
7397            }
7398        }
7399
7400        // Guts of a key/value restore operation
7401        void initiateOneRestore(PackageInfo app, int appVersionCode) {
7402            final String packageName = app.packageName;
7403
7404            if (DEBUG) Slog.d(TAG, "initiateOneRestore packageName=" + packageName);
7405
7406            // !!! TODO: get the dirs from the transport
7407            mBackupDataName = new File(mDataDir, packageName + ".restore");
7408            mStageName = new File(mDataDir, packageName + ".stage");
7409            mNewStateName = new File(mStateDir, packageName + ".new");
7410            mSavedStateName = new File(mStateDir, packageName);
7411
7412            // don't stage the 'android' package where the wallpaper data lives.  this is
7413            // an optimization: we know there's no widget data hosted/published by that
7414            // package, and this way we avoid doing a spurious copy of MB-sized wallpaper
7415            // data following the download.
7416            boolean staging = !packageName.equals("android");
7417            ParcelFileDescriptor stage;
7418            File downloadFile = (staging) ? mStageName : mBackupDataName;
7419
7420            final int token = generateToken();
7421            try {
7422                // Run the transport's restore pass
7423                stage = ParcelFileDescriptor.open(downloadFile,
7424                        ParcelFileDescriptor.MODE_READ_WRITE |
7425                        ParcelFileDescriptor.MODE_CREATE |
7426                        ParcelFileDescriptor.MODE_TRUNCATE);
7427
7428                if (!SELinux.restorecon(mBackupDataName)) {
7429                    Slog.e(TAG, "SElinux restorecon failed for " + downloadFile);
7430                }
7431
7432                if (mTransport.getRestoreData(stage) != BackupTransport.TRANSPORT_OK) {
7433                    // Transport-level failure, so we wind everything up and
7434                    // terminate the restore operation.
7435                    Slog.e(TAG, "Error getting restore data for " + packageName);
7436                    EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
7437                    stage.close();
7438                    downloadFile.delete();
7439                    executeNextState(UnifiedRestoreState.FINAL);
7440                    return;
7441                }
7442
7443                // We have the data from the transport. Now we extract and strip
7444                // any per-package metadata (typically widget-related information)
7445                // if appropriate
7446                if (staging) {
7447                    stage.close();
7448                    stage = ParcelFileDescriptor.open(downloadFile,
7449                            ParcelFileDescriptor.MODE_READ_ONLY);
7450
7451                    mBackupData = ParcelFileDescriptor.open(mBackupDataName,
7452                            ParcelFileDescriptor.MODE_READ_WRITE |
7453                            ParcelFileDescriptor.MODE_CREATE |
7454                            ParcelFileDescriptor.MODE_TRUNCATE);
7455
7456                    BackupDataInput in = new BackupDataInput(stage.getFileDescriptor());
7457                    BackupDataOutput out = new BackupDataOutput(mBackupData.getFileDescriptor());
7458                    byte[] buffer = new byte[8192]; // will grow when needed
7459                    while (in.readNextHeader()) {
7460                        final String key = in.getKey();
7461                        final int size = in.getDataSize();
7462
7463                        // is this a special key?
7464                        if (key.equals(KEY_WIDGET_STATE)) {
7465                            if (DEBUG) {
7466                                Slog.i(TAG, "Restoring widget state for " + packageName);
7467                            }
7468                            mWidgetData = new byte[size];
7469                            in.readEntityData(mWidgetData, 0, size);
7470                        } else {
7471                            if (size > buffer.length) {
7472                                buffer = new byte[size];
7473                            }
7474                            in.readEntityData(buffer, 0, size);
7475                            out.writeEntityHeader(key, size);
7476                            out.writeEntityData(buffer, size);
7477                        }
7478                    }
7479
7480                    mBackupData.close();
7481                }
7482
7483                // Okay, we have the data.  Now have the agent do the restore.
7484                stage.close();
7485                mBackupData = ParcelFileDescriptor.open(mBackupDataName,
7486                        ParcelFileDescriptor.MODE_READ_ONLY);
7487
7488                mNewState = ParcelFileDescriptor.open(mNewStateName,
7489                        ParcelFileDescriptor.MODE_READ_WRITE |
7490                        ParcelFileDescriptor.MODE_CREATE |
7491                        ParcelFileDescriptor.MODE_TRUNCATE);
7492
7493                // Kick off the restore, checking for hung agents.  The timeout or
7494                // the operationComplete() callback will schedule the next step,
7495                // so we do not do that here.
7496                prepareOperationTimeout(token, TIMEOUT_RESTORE_INTERVAL, this);
7497                mAgent.doRestore(mBackupData, appVersionCode, mNewState,
7498                        token, mBackupManagerBinder);
7499            } catch (Exception e) {
7500                Slog.e(TAG, "Unable to call app for restore: " + packageName, e);
7501                EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
7502                        packageName, e.toString());
7503                keyValueAgentErrorCleanup();    // clears any pending timeout messages as well
7504
7505                // After a restore failure we go back to running the queue.  If there
7506                // are no more packages to be restored that will be handled by the
7507                // next step.
7508                executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
7509            }
7510        }
7511
7512        // state RESTORE_FULL : restore one package via streaming engine
7513        private void restoreFull() {
7514            // None of this can run on the work looper here, so we spin asynchronous
7515            // work like this:
7516            //
7517            //   StreamFeederThread: read data from mTransport.getNextFullRestoreDataChunk()
7518            //                       write it into the pipe to the engine
7519            //   EngineThread: FullRestoreEngine thread communicating with the target app
7520            //
7521            // When finished, StreamFeederThread executes next state as appropriate on the
7522            // backup looper, and the overall unified restore task resumes
7523            try {
7524                StreamFeederThread feeder = new StreamFeederThread();
7525                if (DEBUG) {
7526                    Slog.i(TAG, "Spinning threads for stream restore of "
7527                            + mCurrentPackage.packageName);
7528                }
7529                new Thread(feeder, "unified-stream-feeder").start();
7530
7531                // At this point the feeder is responsible for advancing the restore
7532                // state, so we're done here.
7533            } catch (IOException e) {
7534                // Unable to instantiate the feeder thread -- we need to bail on the
7535                // current target.  We haven't asked the transport for data yet, though,
7536                // so we can do that simply by going back to running the restore queue.
7537                Slog.e(TAG, "Unable to construct pipes for stream restore!");
7538                executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
7539            }
7540        }
7541
7542        // state RESTORE_FINISHED : provide the "no more data" signpost callback at the end
7543        private void restoreFinished() {
7544            try {
7545                final int token = generateToken();
7546                prepareOperationTimeout(token, TIMEOUT_RESTORE_FINISHED_INTERVAL, this);
7547                mAgent.doRestoreFinished(token, mBackupManagerBinder);
7548                // If we get this far, the callback or timeout will schedule the
7549                // next restore state, so we're done
7550            } catch (Exception e) {
7551                Slog.e(TAG, "Unable to finalize restore of " + mCurrentPackage.packageName);
7552                executeNextState(UnifiedRestoreState.FINAL);
7553            }
7554        }
7555
7556        class StreamFeederThread extends RestoreEngine implements Runnable {
7557            final String TAG = "StreamFeederThread";
7558            FullRestoreEngine mEngine;
7559
7560            // pipe through which we read data from the transport. [0] read, [1] write
7561            ParcelFileDescriptor[] mTransportPipes;
7562
7563            // pipe through which the engine will read data.  [0] read, [1] write
7564            ParcelFileDescriptor[] mEnginePipes;
7565
7566            public StreamFeederThread() throws IOException {
7567                mTransportPipes = ParcelFileDescriptor.createPipe();
7568                mEnginePipes = ParcelFileDescriptor.createPipe();
7569                setRunning(true);
7570            }
7571
7572            @Override
7573            public void run() {
7574                UnifiedRestoreState nextState = UnifiedRestoreState.RUNNING_QUEUE;
7575                int status = BackupTransport.TRANSPORT_OK;
7576
7577                EventLog.writeEvent(EventLogTags.FULL_RESTORE_PACKAGE,
7578                        mCurrentPackage.packageName);
7579
7580                mEngine = new FullRestoreEngine(null, mCurrentPackage, false, false);
7581                EngineThread eThread = new EngineThread(mEngine, mEnginePipes[0]);
7582
7583                ParcelFileDescriptor eWriteEnd = mEnginePipes[1];
7584                ParcelFileDescriptor tReadEnd = mTransportPipes[0];
7585                ParcelFileDescriptor tWriteEnd = mTransportPipes[1];
7586
7587                int bufferSize = 32 * 1024;
7588                byte[] buffer = new byte[bufferSize];
7589                FileOutputStream engineOut = new FileOutputStream(eWriteEnd.getFileDescriptor());
7590                FileInputStream transportIn = new FileInputStream(tReadEnd.getFileDescriptor());
7591
7592                // spin up the engine and start moving data to it
7593                new Thread(eThread, "unified-restore-engine").start();
7594
7595                try {
7596                    while (status == BackupTransport.TRANSPORT_OK) {
7597                        // have the transport write some of the restoring data to us
7598                        int result = mTransport.getNextFullRestoreDataChunk(tWriteEnd);
7599                        if (result > 0) {
7600                            // The transport wrote this many bytes of restore data to the
7601                            // pipe, so pass it along to the engine.
7602                            if (MORE_DEBUG) {
7603                                Slog.v(TAG, "  <- transport provided chunk size " + result);
7604                            }
7605                            if (result > bufferSize) {
7606                                bufferSize = result;
7607                                buffer = new byte[bufferSize];
7608                            }
7609                            int toCopy = result;
7610                            while (toCopy > 0) {
7611                                int n = transportIn.read(buffer, 0, toCopy);
7612                                engineOut.write(buffer, 0, n);
7613                                toCopy -= n;
7614                                if (MORE_DEBUG) {
7615                                    Slog.v(TAG, "  -> wrote " + n + " to engine, left=" + toCopy);
7616                                }
7617                            }
7618                        } else if (result == BackupTransport.NO_MORE_DATA) {
7619                            // Clean finish.  Wind up and we're done!
7620                            if (MORE_DEBUG) {
7621                                Slog.i(TAG, "Got clean full-restore EOF for "
7622                                        + mCurrentPackage.packageName);
7623                            }
7624                            status = BackupTransport.TRANSPORT_OK;
7625                            break;
7626                        } else {
7627                            // Transport reported some sort of failure; the fall-through
7628                            // handling will deal properly with that.
7629                            Slog.e(TAG, "Error " + result + " streaming restore for "
7630                                    + mCurrentPackage.packageName);
7631                            EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
7632                            status = result;
7633                        }
7634                    }
7635                    if (MORE_DEBUG) Slog.v(TAG, "Done copying to engine, falling through");
7636                } catch (IOException e) {
7637                    // We lost our ability to communicate via the pipes.  That's worrying
7638                    // but potentially recoverable; abandon this package's restore but
7639                    // carry on with the next restore target.
7640                    Slog.e(TAG, "Unable to route data for restore");
7641                    EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
7642                            mCurrentPackage.packageName, "I/O error on pipes");
7643                    status = BackupTransport.AGENT_ERROR;
7644                } catch (RemoteException e) {
7645                    // The transport went away; terminate the whole operation.  Closing
7646                    // the sockets will wake up the engine and it will then tidy up the
7647                    // remote end.
7648                    Slog.e(TAG, "Transport failed during restore");
7649                    EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
7650                    status = BackupTransport.TRANSPORT_ERROR;
7651                } finally {
7652                    // Close the transport pipes and *our* end of the engine pipe,
7653                    // but leave the engine thread's end open so that it properly
7654                    // hits EOF and winds up its operations.
7655                    IoUtils.closeQuietly(mEnginePipes[1]);
7656                    IoUtils.closeQuietly(mTransportPipes[0]);
7657                    IoUtils.closeQuietly(mTransportPipes[1]);
7658
7659                    // Don't proceed until the engine has torn down the agent etc
7660                    eThread.waitForResult();
7661
7662                    if (MORE_DEBUG) {
7663                        Slog.i(TAG, "engine thread finished; proceeding");
7664                    }
7665
7666                    // Now we're really done with this one too
7667                    IoUtils.closeQuietly(mEnginePipes[0]);
7668
7669                    // If we hit a transport-level error, we are done with everything;
7670                    // if we hit an agent error we just go back to running the queue.
7671                    if (status == BackupTransport.TRANSPORT_OK) {
7672                        // Clean finish, so just carry on
7673                        nextState = UnifiedRestoreState.RUNNING_QUEUE;
7674                    } else {
7675                        // Something went wrong somewhere.  Whether it was at the transport
7676                        // level is immaterial; we need to tell the transport to bail
7677                        try {
7678                            mTransport.abortFullRestore();
7679                        } catch (RemoteException e) {
7680                            // transport itself is dead; make sure we handle this as a
7681                            // fatal error
7682                            status = BackupTransport.TRANSPORT_ERROR;
7683                        }
7684
7685                        // We also need to wipe the current target's data, as it's probably
7686                        // in an incoherent state.
7687                        clearApplicationDataSynchronous(mCurrentPackage.packageName);
7688
7689                        // Schedule the next state based on the nature of our failure
7690                        if (status == BackupTransport.TRANSPORT_ERROR) {
7691                            nextState = UnifiedRestoreState.FINAL;
7692                        } else {
7693                            nextState = UnifiedRestoreState.RUNNING_QUEUE;
7694                        }
7695                    }
7696                    executeNextState(nextState);
7697                    setRunning(false);
7698                }
7699            }
7700
7701        }
7702
7703        class EngineThread implements Runnable {
7704            FullRestoreEngine mEngine;
7705            FileInputStream mEngineStream;
7706
7707            EngineThread(FullRestoreEngine engine, ParcelFileDescriptor engineSocket) {
7708                mEngine = engine;
7709                engine.setRunning(true);
7710                mEngineStream = new FileInputStream(engineSocket.getFileDescriptor());
7711            }
7712
7713            public boolean isRunning() {
7714                return mEngine.isRunning();
7715            }
7716
7717            public int waitForResult() {
7718                return mEngine.waitForResult();
7719            }
7720
7721            @Override
7722            public void run() {
7723                while (mEngine.isRunning()) {
7724                    mEngine.restoreOneFile(mEngineStream);
7725                }
7726            }
7727        }
7728
7729        // state FINAL : tear everything down and we're done.
7730        private void finalizeRestore() {
7731            if (MORE_DEBUG) Slog.d(TAG, "finishing restore mObserver=" + mObserver);
7732
7733            try {
7734                mTransport.finishRestore();
7735            } catch (Exception e) {
7736                Slog.e(TAG, "Error finishing restore", e);
7737            }
7738
7739            // Tell the observer we're done
7740            if (mObserver != null) {
7741                try {
7742                    mObserver.restoreFinished(mStatus);
7743                } catch (RemoteException e) {
7744                    Slog.d(TAG, "Restore observer died at restoreFinished");
7745                }
7746            }
7747
7748            // Clear any ongoing session timeout.
7749            mBackupHandler.removeMessages(MSG_RESTORE_TIMEOUT);
7750
7751            // If we have a PM token, we must under all circumstances be sure to
7752            // handshake when we've finished.
7753            if (mPmToken > 0) {
7754                if (MORE_DEBUG) Slog.v(TAG, "finishing PM token " + mPmToken);
7755                try {
7756                    mPackageManagerBinder.finishPackageInstall(mPmToken);
7757                } catch (RemoteException e) { /* can't happen */ }
7758            } else {
7759                // We were invoked via an active restore session, not by the Package
7760                // Manager, so start up the session timeout again.
7761                mBackupHandler.sendEmptyMessageDelayed(MSG_RESTORE_TIMEOUT,
7762                        TIMEOUT_RESTORE_INTERVAL);
7763            }
7764
7765            // Kick off any work that may be needed regarding app widget restores
7766            AppWidgetBackupBridge.restoreFinished(UserHandle.USER_OWNER);
7767
7768            // If this was a full-system restore, record the ancestral
7769            // dataset information
7770            if (mIsSystemRestore && mPmAgent != null) {
7771                mAncestralPackages = mPmAgent.getRestoredPackages();
7772                mAncestralToken = mToken;
7773                writeRestoreTokens();
7774            }
7775
7776            // done; we can finally release the wakelock and be legitimately done.
7777            Slog.i(TAG, "Restore complete.");
7778            mWakelock.release();
7779        }
7780
7781        void keyValueAgentErrorCleanup() {
7782            // If the agent fails restore, it might have put the app's data
7783            // into an incoherent state.  For consistency we wipe its data
7784            // again in this case before continuing with normal teardown
7785            clearApplicationDataSynchronous(mCurrentPackage.packageName);
7786            keyValueAgentCleanup();
7787        }
7788
7789        void keyValueAgentCleanup() {
7790            mBackupDataName.delete();
7791            mStageName.delete();
7792            try { if (mBackupData != null) mBackupData.close(); } catch (IOException e) {}
7793            try { if (mNewState != null) mNewState.close(); } catch (IOException e) {}
7794            mBackupData = mNewState = null;
7795
7796            // if everything went okay, remember the recorded state now
7797            //
7798            // !!! TODO: the restored data could be migrated on the server
7799            // side into the current dataset.  In that case the new state file
7800            // we just created would reflect the data already extant in the
7801            // backend, so there'd be nothing more to do.  Until that happens,
7802            // however, we need to make sure that we record the data to the
7803            // current backend dataset.  (Yes, this means shipping the data over
7804            // the wire in both directions.  That's bad, but consistency comes
7805            // first, then efficiency.)  Once we introduce server-side data
7806            // migration to the newly-restored device's dataset, we will change
7807            // the following from a discard of the newly-written state to the
7808            // "correct" operation of renaming into the canonical state blob.
7809            mNewStateName.delete();                      // TODO: remove; see above comment
7810            //mNewStateName.renameTo(mSavedStateName);   // TODO: replace with this
7811
7812            // If this wasn't the PM pseudopackage, tear down the agent side
7813            if (mCurrentPackage.applicationInfo != null) {
7814                // unbind and tidy up even on timeout or failure
7815                try {
7816                    mActivityManager.unbindBackupAgent(mCurrentPackage.applicationInfo);
7817
7818                    // The agent was probably running with a stub Application object,
7819                    // which isn't a valid run mode for the main app logic.  Shut
7820                    // down the app so that next time it's launched, it gets the
7821                    // usual full initialization.  Note that this is only done for
7822                    // full-system restores: when a single app has requested a restore,
7823                    // it is explicitly not killed following that operation.
7824                    if (mTargetPackage == null && (mCurrentPackage.applicationInfo.flags
7825                            & ApplicationInfo.FLAG_KILL_AFTER_RESTORE) != 0) {
7826                        if (DEBUG) Slog.d(TAG, "Restore complete, killing host process of "
7827                                + mCurrentPackage.applicationInfo.processName);
7828                        mActivityManager.killApplicationProcess(
7829                                mCurrentPackage.applicationInfo.processName,
7830                                mCurrentPackage.applicationInfo.uid);
7831                    }
7832                } catch (RemoteException e) {
7833                    // can't happen; we run in the same process as the activity manager
7834                }
7835            }
7836
7837            // The caller is responsible for reestablishing the state machine; our
7838            // responsibility here is to clear the decks for whatever comes next.
7839            mBackupHandler.removeMessages(MSG_TIMEOUT, this);
7840            synchronized (mCurrentOpLock) {
7841                mCurrentOperations.clear();
7842            }
7843        }
7844
7845        @Override
7846        public void operationComplete() {
7847            if (MORE_DEBUG) {
7848                Slog.i(TAG, "operationComplete() during restore: target="
7849                        + mCurrentPackage.packageName
7850                        + " state=" + mState);
7851            }
7852
7853            final UnifiedRestoreState nextState;
7854            switch (mState) {
7855                case INITIAL:
7856                    // We've just (manually) restored the PMBA.  It doesn't need the
7857                    // additional restore-finished callback so we bypass that and go
7858                    // directly to running the queue.
7859                    nextState = UnifiedRestoreState.RUNNING_QUEUE;
7860                    break;
7861
7862                case RESTORE_KEYVALUE:
7863                case RESTORE_FULL: {
7864                    // Okay, we've just heard back from the agent that it's done with
7865                    // the restore itself.  We now have to send the same agent its
7866                    // doRestoreFinished() callback, so roll into that state.
7867                    nextState = UnifiedRestoreState.RESTORE_FINISHED;
7868                    break;
7869                }
7870
7871                case RESTORE_FINISHED: {
7872                    // Okay, we're done with this package.  Tidy up and go on to the next
7873                    // app in the queue.
7874                    int size = (int) mBackupDataName.length();
7875                    EventLog.writeEvent(EventLogTags.RESTORE_PACKAGE,
7876                            mCurrentPackage.packageName, size);
7877
7878                    // Just go back to running the restore queue
7879                    keyValueAgentCleanup();
7880
7881                    // If there was widget state associated with this app, get the OS to
7882                    // incorporate it into current bookeeping and then pass that along to
7883                    // the app as part of the restore-time work.
7884                    if (mWidgetData != null) {
7885                        restoreWidgetData(mCurrentPackage.packageName, mWidgetData);
7886                    }
7887
7888                    nextState = UnifiedRestoreState.RUNNING_QUEUE;
7889                    break;
7890                }
7891
7892                default: {
7893                    // Some kind of horrible semantic error; we're in an unexpected state.
7894                    // Back off hard and wind up.
7895                    Slog.e(TAG, "Unexpected restore callback into state " + mState);
7896                    keyValueAgentErrorCleanup();
7897                    nextState = UnifiedRestoreState.FINAL;
7898                    break;
7899                }
7900            }
7901
7902            executeNextState(nextState);
7903        }
7904
7905        // A call to agent.doRestore() or agent.doRestoreFinished() has timed out
7906        @Override
7907        public void handleTimeout() {
7908            Slog.e(TAG, "Timeout restoring application " + mCurrentPackage.packageName);
7909            EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
7910                    mCurrentPackage.packageName, "restore timeout");
7911            // Handle like an agent that threw on invocation: wipe it and go on to the next
7912            keyValueAgentErrorCleanup();
7913            executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
7914        }
7915
7916        void executeNextState(UnifiedRestoreState nextState) {
7917            if (MORE_DEBUG) Slog.i(TAG, " => executing next step on "
7918                    + this + " nextState=" + nextState);
7919            mState = nextState;
7920            Message msg = mBackupHandler.obtainMessage(MSG_BACKUP_RESTORE_STEP, this);
7921            mBackupHandler.sendMessage(msg);
7922        }
7923
7924        // restore observer support
7925        void sendStartRestore(int numPackages) {
7926            if (mObserver != null) {
7927                try {
7928                    mObserver.restoreStarting(numPackages);
7929                } catch (RemoteException e) {
7930                    Slog.w(TAG, "Restore observer went away: startRestore");
7931                    mObserver = null;
7932                }
7933            }
7934        }
7935
7936        void sendOnRestorePackage(String name) {
7937            if (mObserver != null) {
7938                if (mObserver != null) {
7939                    try {
7940                        mObserver.onUpdate(mCount, name);
7941                    } catch (RemoteException e) {
7942                        Slog.d(TAG, "Restore observer died in onUpdate");
7943                        mObserver = null;
7944                    }
7945                }
7946            }
7947        }
7948
7949        void sendEndRestore() {
7950            if (mObserver != null) {
7951                try {
7952                    mObserver.restoreFinished(mStatus);
7953                } catch (RemoteException e) {
7954                    Slog.w(TAG, "Restore observer went away: endRestore");
7955                    mObserver = null;
7956                }
7957            }
7958        }
7959    }
7960
7961    class PerformClearTask implements Runnable {
7962        IBackupTransport mTransport;
7963        PackageInfo mPackage;
7964
7965        PerformClearTask(IBackupTransport transport, PackageInfo packageInfo) {
7966            mTransport = transport;
7967            mPackage = packageInfo;
7968        }
7969
7970        public void run() {
7971            try {
7972                // Clear the on-device backup state to ensure a full backup next time
7973                File stateDir = new File(mBaseStateDir, mTransport.transportDirName());
7974                File stateFile = new File(stateDir, mPackage.packageName);
7975                stateFile.delete();
7976
7977                // Tell the transport to remove all the persistent storage for the app
7978                // TODO - need to handle failures
7979                mTransport.clearBackupData(mPackage);
7980            } catch (RemoteException e) {
7981                // can't happen; the transport is local
7982            } catch (Exception e) {
7983                Slog.e(TAG, "Transport threw attempting to clear data for " + mPackage);
7984            } finally {
7985                try {
7986                    // TODO - need to handle failures
7987                    mTransport.finishBackup();
7988                } catch (RemoteException e) {
7989                    // can't happen; the transport is local
7990                }
7991
7992                // Last but not least, release the cpu
7993                mWakelock.release();
7994            }
7995        }
7996    }
7997
7998    class PerformInitializeTask implements Runnable {
7999        HashSet<String> mQueue;
8000
8001        PerformInitializeTask(HashSet<String> transportNames) {
8002            mQueue = transportNames;
8003        }
8004
8005        public void run() {
8006            try {
8007                for (String transportName : mQueue) {
8008                    IBackupTransport transport = getTransport(transportName);
8009                    if (transport == null) {
8010                        Slog.e(TAG, "Requested init for " + transportName + " but not found");
8011                        continue;
8012                    }
8013
8014                    Slog.i(TAG, "Initializing (wiping) backup transport storage: " + transportName);
8015                    EventLog.writeEvent(EventLogTags.BACKUP_START, transport.transportDirName());
8016                    long startRealtime = SystemClock.elapsedRealtime();
8017                    int status = transport.initializeDevice();
8018
8019                    if (status == BackupTransport.TRANSPORT_OK) {
8020                        status = transport.finishBackup();
8021                    }
8022
8023                    // Okay, the wipe really happened.  Clean up our local bookkeeping.
8024                    if (status == BackupTransport.TRANSPORT_OK) {
8025                        Slog.i(TAG, "Device init successful");
8026                        int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
8027                        EventLog.writeEvent(EventLogTags.BACKUP_INITIALIZE);
8028                        resetBackupState(new File(mBaseStateDir, transport.transportDirName()));
8029                        EventLog.writeEvent(EventLogTags.BACKUP_SUCCESS, 0, millis);
8030                        synchronized (mQueueLock) {
8031                            recordInitPendingLocked(false, transportName);
8032                        }
8033                    } else {
8034                        // If this didn't work, requeue this one and try again
8035                        // after a suitable interval
8036                        Slog.e(TAG, "Transport error in initializeDevice()");
8037                        EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, "(initialize)");
8038                        synchronized (mQueueLock) {
8039                            recordInitPendingLocked(true, transportName);
8040                        }
8041                        // do this via another alarm to make sure of the wakelock states
8042                        long delay = transport.requestBackupTime();
8043                        if (DEBUG) Slog.w(TAG, "init failed on "
8044                                + transportName + " resched in " + delay);
8045                        mAlarmManager.set(AlarmManager.RTC_WAKEUP,
8046                                System.currentTimeMillis() + delay, mRunInitIntent);
8047                    }
8048                }
8049            } catch (RemoteException e) {
8050                // can't happen; the transports are local
8051            } catch (Exception e) {
8052                Slog.e(TAG, "Unexpected error performing init", e);
8053            } finally {
8054                // Done; release the wakelock
8055                mWakelock.release();
8056            }
8057        }
8058    }
8059
8060    private void dataChangedImpl(String packageName) {
8061        HashSet<String> targets = dataChangedTargets(packageName);
8062        dataChangedImpl(packageName, targets);
8063    }
8064
8065    private void dataChangedImpl(String packageName, HashSet<String> targets) {
8066        // Record that we need a backup pass for the caller.  Since multiple callers
8067        // may share a uid, we need to note all candidates within that uid and schedule
8068        // a backup pass for each of them.
8069        if (targets == null) {
8070            Slog.w(TAG, "dataChanged but no participant pkg='" + packageName + "'"
8071                   + " uid=" + Binder.getCallingUid());
8072            return;
8073        }
8074
8075        synchronized (mQueueLock) {
8076            // Note that this client has made data changes that need to be backed up
8077            if (targets.contains(packageName)) {
8078                // Add the caller to the set of pending backups.  If there is
8079                // one already there, then overwrite it, but no harm done.
8080                BackupRequest req = new BackupRequest(packageName);
8081                if (mPendingBackups.put(packageName, req) == null) {
8082                    if (DEBUG) Slog.d(TAG, "Now staging backup of " + packageName);
8083
8084                    // Journal this request in case of crash.  The put()
8085                    // operation returned null when this package was not already
8086                    // in the set; we want to avoid touching the disk redundantly.
8087                    writeToJournalLocked(packageName);
8088
8089                    if (MORE_DEBUG) {
8090                        int numKeys = mPendingBackups.size();
8091                        Slog.d(TAG, "Now awaiting backup for " + numKeys + " participants:");
8092                        for (BackupRequest b : mPendingBackups.values()) {
8093                            Slog.d(TAG, "    + " + b);
8094                        }
8095                    }
8096                }
8097            }
8098        }
8099    }
8100
8101    // Note: packageName is currently unused, but may be in the future
8102    private HashSet<String> dataChangedTargets(String packageName) {
8103        // If the caller does not hold the BACKUP permission, it can only request a
8104        // backup of its own data.
8105        if ((mContext.checkPermission(android.Manifest.permission.BACKUP, Binder.getCallingPid(),
8106                Binder.getCallingUid())) == PackageManager.PERMISSION_DENIED) {
8107            synchronized (mBackupParticipants) {
8108                return mBackupParticipants.get(Binder.getCallingUid());
8109            }
8110        }
8111
8112        // a caller with full permission can ask to back up any participating app
8113        // !!! TODO: allow backup of ANY app?
8114        HashSet<String> targets = new HashSet<String>();
8115        synchronized (mBackupParticipants) {
8116            int N = mBackupParticipants.size();
8117            for (int i = 0; i < N; i++) {
8118                HashSet<String> s = mBackupParticipants.valueAt(i);
8119                if (s != null) {
8120                    targets.addAll(s);
8121                }
8122            }
8123        }
8124        return targets;
8125    }
8126
8127    private void writeToJournalLocked(String str) {
8128        RandomAccessFile out = null;
8129        try {
8130            if (mJournal == null) mJournal = File.createTempFile("journal", null, mJournalDir);
8131            out = new RandomAccessFile(mJournal, "rws");
8132            out.seek(out.length());
8133            out.writeUTF(str);
8134        } catch (IOException e) {
8135            Slog.e(TAG, "Can't write " + str + " to backup journal", e);
8136            mJournal = null;
8137        } finally {
8138            try { if (out != null) out.close(); } catch (IOException e) {}
8139        }
8140    }
8141
8142    // ----- IBackupManager binder interface -----
8143
8144    public void dataChanged(final String packageName) {
8145        final int callingUserHandle = UserHandle.getCallingUserId();
8146        if (callingUserHandle != UserHandle.USER_OWNER) {
8147            // App is running under a non-owner user profile.  For now, we do not back
8148            // up data from secondary user profiles.
8149            // TODO: backups for all user profiles.
8150            if (MORE_DEBUG) {
8151                Slog.v(TAG, "dataChanged(" + packageName + ") ignored because it's user "
8152                        + callingUserHandle);
8153            }
8154            return;
8155        }
8156
8157        final HashSet<String> targets = dataChangedTargets(packageName);
8158        if (targets == null) {
8159            Slog.w(TAG, "dataChanged but no participant pkg='" + packageName + "'"
8160                   + " uid=" + Binder.getCallingUid());
8161            return;
8162        }
8163
8164        mBackupHandler.post(new Runnable() {
8165                public void run() {
8166                    dataChangedImpl(packageName, targets);
8167                }
8168            });
8169    }
8170
8171    // Clear the given package's backup data from the current transport
8172    public void clearBackupData(String transportName, String packageName) {
8173        if (DEBUG) Slog.v(TAG, "clearBackupData() of " + packageName + " on " + transportName);
8174        PackageInfo info;
8175        try {
8176            info = mPackageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
8177        } catch (NameNotFoundException e) {
8178            Slog.d(TAG, "No such package '" + packageName + "' - not clearing backup data");
8179            return;
8180        }
8181
8182        // If the caller does not hold the BACKUP permission, it can only request a
8183        // wipe of its own backed-up data.
8184        HashSet<String> apps;
8185        if ((mContext.checkPermission(android.Manifest.permission.BACKUP, Binder.getCallingPid(),
8186                Binder.getCallingUid())) == PackageManager.PERMISSION_DENIED) {
8187            apps = mBackupParticipants.get(Binder.getCallingUid());
8188        } else {
8189            // a caller with full permission can ask to back up any participating app
8190            // !!! TODO: allow data-clear of ANY app?
8191            if (DEBUG) Slog.v(TAG, "Privileged caller, allowing clear of other apps");
8192            apps = new HashSet<String>();
8193            int N = mBackupParticipants.size();
8194            for (int i = 0; i < N; i++) {
8195                HashSet<String> s = mBackupParticipants.valueAt(i);
8196                if (s != null) {
8197                    apps.addAll(s);
8198                }
8199            }
8200        }
8201
8202        // Is the given app an available participant?
8203        if (apps.contains(packageName)) {
8204            // found it; fire off the clear request
8205            if (DEBUG) Slog.v(TAG, "Found the app - running clear process");
8206            mBackupHandler.removeMessages(MSG_RETRY_CLEAR);
8207            synchronized (mQueueLock) {
8208                final IBackupTransport transport = getTransport(transportName);
8209                if (transport == null) {
8210                    // transport is currently unavailable -- make sure to retry
8211                    Message msg = mBackupHandler.obtainMessage(MSG_RETRY_CLEAR,
8212                            new ClearRetryParams(transportName, packageName));
8213                    mBackupHandler.sendMessageDelayed(msg, TRANSPORT_RETRY_INTERVAL);
8214                    return;
8215                }
8216                long oldId = Binder.clearCallingIdentity();
8217                mWakelock.acquire();
8218                Message msg = mBackupHandler.obtainMessage(MSG_RUN_CLEAR,
8219                        new ClearParams(transport, info));
8220                mBackupHandler.sendMessage(msg);
8221                Binder.restoreCallingIdentity(oldId);
8222            }
8223        }
8224    }
8225
8226    // Run a backup pass immediately for any applications that have declared
8227    // that they have pending updates.
8228    public void backupNow() {
8229        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "backupNow");
8230
8231        if (DEBUG) Slog.v(TAG, "Scheduling immediate backup pass");
8232        synchronized (mQueueLock) {
8233            // Because the alarms we are using can jitter, and we want an *immediate*
8234            // backup pass to happen, we restart the timer beginning with "next time,"
8235            // then manually fire the backup trigger intent ourselves.
8236            startBackupAlarmsLocked(BACKUP_INTERVAL);
8237            try {
8238                mRunBackupIntent.send();
8239            } catch (PendingIntent.CanceledException e) {
8240                // should never happen
8241                Slog.e(TAG, "run-backup intent cancelled!");
8242            }
8243        }
8244    }
8245
8246    boolean deviceIsProvisioned() {
8247        final ContentResolver resolver = mContext.getContentResolver();
8248        return (Settings.Global.getInt(resolver, Settings.Global.DEVICE_PROVISIONED, 0) != 0);
8249    }
8250
8251    // Run a *full* backup pass for the given packages, writing the resulting data stream
8252    // to the supplied file descriptor.  This method is synchronous and does not return
8253    // to the caller until the backup has been completed.
8254    //
8255    // This is the variant used by 'adb backup'; it requires on-screen confirmation
8256    // by the user because it can be used to offload data over untrusted USB.
8257    public void fullBackup(ParcelFileDescriptor fd, boolean includeApks,
8258            boolean includeObbs, boolean includeShared, boolean doWidgets,
8259            boolean doAllApps, boolean includeSystem, boolean compress, String[] pkgList) {
8260        mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "fullBackup");
8261
8262        final int callingUserHandle = UserHandle.getCallingUserId();
8263        if (callingUserHandle != UserHandle.USER_OWNER) {
8264            throw new IllegalStateException("Backup supported only for the device owner");
8265        }
8266
8267        // Validate
8268        if (!doAllApps) {
8269            if (!includeShared) {
8270                // If we're backing up shared data (sdcard or equivalent), then we can run
8271                // without any supplied app names.  Otherwise, we'd be doing no work, so
8272                // report the error.
8273                if (pkgList == null || pkgList.length == 0) {
8274                    throw new IllegalArgumentException(
8275                            "Backup requested but neither shared nor any apps named");
8276                }
8277            }
8278        }
8279
8280        long oldId = Binder.clearCallingIdentity();
8281        try {
8282            // Doesn't make sense to do a full backup prior to setup
8283            if (!deviceIsProvisioned()) {
8284                Slog.i(TAG, "Full backup not supported before setup");
8285                return;
8286            }
8287
8288            if (DEBUG) Slog.v(TAG, "Requesting full backup: apks=" + includeApks
8289                    + " obb=" + includeObbs + " shared=" + includeShared + " all=" + doAllApps
8290                    + " system=" + includeSystem + " pkgs=" + pkgList);
8291            Slog.i(TAG, "Beginning full backup...");
8292
8293            FullBackupParams params = new FullBackupParams(fd, includeApks, includeObbs,
8294                    includeShared, doWidgets, doAllApps, includeSystem, compress, pkgList);
8295            final int token = generateToken();
8296            synchronized (mFullConfirmations) {
8297                mFullConfirmations.put(token, params);
8298            }
8299
8300            // start up the confirmation UI
8301            if (DEBUG) Slog.d(TAG, "Starting backup confirmation UI, token=" + token);
8302            if (!startConfirmationUi(token, FullBackup.FULL_BACKUP_INTENT_ACTION)) {
8303                Slog.e(TAG, "Unable to launch full backup confirmation");
8304                mFullConfirmations.delete(token);
8305                return;
8306            }
8307
8308            // make sure the screen is lit for the user interaction
8309            mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
8310
8311            // start the confirmation countdown
8312            startConfirmationTimeout(token, params);
8313
8314            // wait for the backup to be performed
8315            if (DEBUG) Slog.d(TAG, "Waiting for full backup completion...");
8316            waitForCompletion(params);
8317        } finally {
8318            try {
8319                fd.close();
8320            } catch (IOException e) {
8321                // just eat it
8322            }
8323            Binder.restoreCallingIdentity(oldId);
8324            Slog.d(TAG, "Full backup processing complete.");
8325        }
8326    }
8327
8328    public void fullTransportBackup(String[] pkgNames) {
8329        mContext.enforceCallingPermission(android.Manifest.permission.BACKUP,
8330                "fullTransportBackup");
8331
8332        final int callingUserHandle = UserHandle.getCallingUserId();
8333        if (callingUserHandle != UserHandle.USER_OWNER) {
8334            throw new IllegalStateException("Restore supported only for the device owner");
8335        }
8336
8337        if (DEBUG) {
8338            Slog.d(TAG, "fullTransportBackup()");
8339        }
8340
8341        AtomicBoolean latch = new AtomicBoolean(false);
8342        PerformFullTransportBackupTask task =
8343                new PerformFullTransportBackupTask(null, pkgNames, false, null, latch);
8344        (new Thread(task, "full-transport-master")).start();
8345        synchronized (latch) {
8346            try {
8347                while (latch.get() == false) {
8348                    latch.wait();
8349                }
8350            } catch (InterruptedException e) {}
8351        }
8352        if (DEBUG) {
8353            Slog.d(TAG, "Done with full transport backup.");
8354        }
8355    }
8356
8357    public void fullRestore(ParcelFileDescriptor fd) {
8358        mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "fullRestore");
8359
8360        final int callingUserHandle = UserHandle.getCallingUserId();
8361        if (callingUserHandle != UserHandle.USER_OWNER) {
8362            throw new IllegalStateException("Restore supported only for the device owner");
8363        }
8364
8365        long oldId = Binder.clearCallingIdentity();
8366
8367        try {
8368            // Check whether the device has been provisioned -- we don't handle
8369            // full restores prior to completing the setup process.
8370            if (!deviceIsProvisioned()) {
8371                Slog.i(TAG, "Full restore not permitted before setup");
8372                return;
8373            }
8374
8375            Slog.i(TAG, "Beginning full restore...");
8376
8377            FullRestoreParams params = new FullRestoreParams(fd);
8378            final int token = generateToken();
8379            synchronized (mFullConfirmations) {
8380                mFullConfirmations.put(token, params);
8381            }
8382
8383            // start up the confirmation UI
8384            if (DEBUG) Slog.d(TAG, "Starting restore confirmation UI, token=" + token);
8385            if (!startConfirmationUi(token, FullBackup.FULL_RESTORE_INTENT_ACTION)) {
8386                Slog.e(TAG, "Unable to launch full restore confirmation");
8387                mFullConfirmations.delete(token);
8388                return;
8389            }
8390
8391            // make sure the screen is lit for the user interaction
8392            mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
8393
8394            // start the confirmation countdown
8395            startConfirmationTimeout(token, params);
8396
8397            // wait for the restore to be performed
8398            if (DEBUG) Slog.d(TAG, "Waiting for full restore completion...");
8399            waitForCompletion(params);
8400        } finally {
8401            try {
8402                fd.close();
8403            } catch (IOException e) {
8404                Slog.w(TAG, "Error trying to close fd after full restore: " + e);
8405            }
8406            Binder.restoreCallingIdentity(oldId);
8407            Slog.i(TAG, "Full restore processing complete.");
8408        }
8409    }
8410
8411    boolean startConfirmationUi(int token, String action) {
8412        try {
8413            Intent confIntent = new Intent(action);
8414            confIntent.setClassName("com.android.backupconfirm",
8415                    "com.android.backupconfirm.BackupRestoreConfirmation");
8416            confIntent.putExtra(FullBackup.CONF_TOKEN_INTENT_EXTRA, token);
8417            confIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8418            mContext.startActivity(confIntent);
8419        } catch (ActivityNotFoundException e) {
8420            return false;
8421        }
8422        return true;
8423    }
8424
8425    void startConfirmationTimeout(int token, FullParams params) {
8426        if (MORE_DEBUG) Slog.d(TAG, "Posting conf timeout msg after "
8427                + TIMEOUT_FULL_CONFIRMATION + " millis");
8428        Message msg = mBackupHandler.obtainMessage(MSG_FULL_CONFIRMATION_TIMEOUT,
8429                token, 0, params);
8430        mBackupHandler.sendMessageDelayed(msg, TIMEOUT_FULL_CONFIRMATION);
8431    }
8432
8433    void waitForCompletion(FullParams params) {
8434        synchronized (params.latch) {
8435            while (params.latch.get() == false) {
8436                try {
8437                    params.latch.wait();
8438                } catch (InterruptedException e) { /* never interrupted */ }
8439            }
8440        }
8441    }
8442
8443    void signalFullBackupRestoreCompletion(FullParams params) {
8444        synchronized (params.latch) {
8445            params.latch.set(true);
8446            params.latch.notifyAll();
8447        }
8448    }
8449
8450    // Confirm that the previously-requested full backup/restore operation can proceed.  This
8451    // is used to require a user-facing disclosure about the operation.
8452    public void acknowledgeFullBackupOrRestore(int token, boolean allow,
8453            String curPassword, String encPpassword, IFullBackupRestoreObserver observer) {
8454        if (DEBUG) Slog.d(TAG, "acknowledgeFullBackupOrRestore : token=" + token
8455                + " allow=" + allow);
8456
8457        // TODO: possibly require not just this signature-only permission, but even
8458        // require that the specific designated confirmation-UI app uid is the caller?
8459        mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "acknowledgeFullBackupOrRestore");
8460
8461        long oldId = Binder.clearCallingIdentity();
8462        try {
8463
8464            FullParams params;
8465            synchronized (mFullConfirmations) {
8466                params = mFullConfirmations.get(token);
8467                if (params != null) {
8468                    mBackupHandler.removeMessages(MSG_FULL_CONFIRMATION_TIMEOUT, params);
8469                    mFullConfirmations.delete(token);
8470
8471                    if (allow) {
8472                        final int verb = params instanceof FullBackupParams
8473                                ? MSG_RUN_ADB_BACKUP
8474                                : MSG_RUN_ADB_RESTORE;
8475
8476                        params.observer = observer;
8477                        params.curPassword = curPassword;
8478
8479                        params.encryptPassword = encPpassword;
8480
8481                        if (DEBUG) Slog.d(TAG, "Sending conf message with verb " + verb);
8482                        mWakelock.acquire();
8483                        Message msg = mBackupHandler.obtainMessage(verb, params);
8484                        mBackupHandler.sendMessage(msg);
8485                    } else {
8486                        Slog.w(TAG, "User rejected full backup/restore operation");
8487                        // indicate completion without having actually transferred any data
8488                        signalFullBackupRestoreCompletion(params);
8489                    }
8490                } else {
8491                    Slog.w(TAG, "Attempted to ack full backup/restore with invalid token");
8492                }
8493            }
8494        } finally {
8495            Binder.restoreCallingIdentity(oldId);
8496        }
8497    }
8498
8499    // Enable/disable backups
8500    public void setBackupEnabled(boolean enable) {
8501        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
8502                "setBackupEnabled");
8503
8504        Slog.i(TAG, "Backup enabled => " + enable);
8505
8506        long oldId = Binder.clearCallingIdentity();
8507        try {
8508            boolean wasEnabled = mEnabled;
8509            synchronized (this) {
8510                Settings.Secure.putInt(mContext.getContentResolver(),
8511                        Settings.Secure.BACKUP_ENABLED, enable ? 1 : 0);
8512                mEnabled = enable;
8513            }
8514
8515            synchronized (mQueueLock) {
8516                if (enable && !wasEnabled && mProvisioned) {
8517                    // if we've just been enabled, start scheduling backup passes
8518                    startBackupAlarmsLocked(BACKUP_INTERVAL);
8519                    scheduleNextFullBackupJob();
8520                } else if (!enable) {
8521                    // No longer enabled, so stop running backups
8522                    if (DEBUG) Slog.i(TAG, "Opting out of backup");
8523
8524                    mAlarmManager.cancel(mRunBackupIntent);
8525
8526                    // This also constitutes an opt-out, so we wipe any data for
8527                    // this device from the backend.  We start that process with
8528                    // an alarm in order to guarantee wakelock states.
8529                    if (wasEnabled && mProvisioned) {
8530                        // NOTE: we currently flush every registered transport, not just
8531                        // the currently-active one.
8532                        HashSet<String> allTransports;
8533                        synchronized (mTransports) {
8534                            allTransports = new HashSet<String>(mTransports.keySet());
8535                        }
8536                        // build the set of transports for which we are posting an init
8537                        for (String transport : allTransports) {
8538                            recordInitPendingLocked(true, transport);
8539                        }
8540                        mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
8541                                mRunInitIntent);
8542                    }
8543                }
8544            }
8545        } finally {
8546            Binder.restoreCallingIdentity(oldId);
8547        }
8548    }
8549
8550    // Enable/disable automatic restore of app data at install time
8551    public void setAutoRestore(boolean doAutoRestore) {
8552        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
8553                "setAutoRestore");
8554
8555        Slog.i(TAG, "Auto restore => " + doAutoRestore);
8556
8557        final long oldId = Binder.clearCallingIdentity();
8558        try {
8559            synchronized (this) {
8560                Settings.Secure.putInt(mContext.getContentResolver(),
8561                        Settings.Secure.BACKUP_AUTO_RESTORE, doAutoRestore ? 1 : 0);
8562                mAutoRestore = doAutoRestore;
8563            }
8564        } finally {
8565            Binder.restoreCallingIdentity(oldId);
8566        }
8567    }
8568
8569    // Mark the backup service as having been provisioned
8570    public void setBackupProvisioned(boolean available) {
8571        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
8572                "setBackupProvisioned");
8573        /*
8574         * This is now a no-op; provisioning is simply the device's own setup state.
8575         */
8576    }
8577
8578    private void startBackupAlarmsLocked(long delayBeforeFirstBackup) {
8579        // We used to use setInexactRepeating(), but that may be linked to
8580        // backups running at :00 more often than not, creating load spikes.
8581        // Schedule at an exact time for now, and also add a bit of "fuzz".
8582
8583        Random random = new Random();
8584        long when = System.currentTimeMillis() + delayBeforeFirstBackup +
8585                random.nextInt(FUZZ_MILLIS);
8586        mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, when,
8587                BACKUP_INTERVAL + random.nextInt(FUZZ_MILLIS), mRunBackupIntent);
8588        mNextBackupPass = when;
8589    }
8590
8591    // Report whether the backup mechanism is currently enabled
8592    public boolean isBackupEnabled() {
8593        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "isBackupEnabled");
8594        return mEnabled;    // no need to synchronize just to read it
8595    }
8596
8597    // Report the name of the currently active transport
8598    public String getCurrentTransport() {
8599        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
8600                "getCurrentTransport");
8601        if (MORE_DEBUG) Slog.v(TAG, "... getCurrentTransport() returning " + mCurrentTransport);
8602        return mCurrentTransport;
8603    }
8604
8605    // Report all known, available backup transports
8606    public String[] listAllTransports() {
8607        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "listAllTransports");
8608
8609        String[] list = null;
8610        ArrayList<String> known = new ArrayList<String>();
8611        for (Map.Entry<String, IBackupTransport> entry : mTransports.entrySet()) {
8612            if (entry.getValue() != null) {
8613                known.add(entry.getKey());
8614            }
8615        }
8616
8617        if (known.size() > 0) {
8618            list = new String[known.size()];
8619            known.toArray(list);
8620        }
8621        return list;
8622    }
8623
8624    // Select which transport to use for the next backup operation.
8625    public String selectBackupTransport(String transport) {
8626        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
8627                "selectBackupTransport");
8628
8629        synchronized (mTransports) {
8630            final long oldId = Binder.clearCallingIdentity();
8631            try {
8632                String prevTransport = mCurrentTransport;
8633                mCurrentTransport = transport;
8634                Settings.Secure.putString(mContext.getContentResolver(),
8635                        Settings.Secure.BACKUP_TRANSPORT, transport);
8636                Slog.v(TAG, "selectBackupTransport() set " + mCurrentTransport
8637                        + " returning " + prevTransport);
8638                return prevTransport;
8639            } finally {
8640                Binder.restoreCallingIdentity(oldId);
8641            }
8642        }
8643    }
8644
8645    // Supply the configuration Intent for the given transport.  If the name is not one
8646    // of the available transports, or if the transport does not supply any configuration
8647    // UI, the method returns null.
8648    public Intent getConfigurationIntent(String transportName) {
8649        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
8650                "getConfigurationIntent");
8651
8652        synchronized (mTransports) {
8653            final IBackupTransport transport = mTransports.get(transportName);
8654            if (transport != null) {
8655                try {
8656                    final Intent intent = transport.configurationIntent();
8657                    if (MORE_DEBUG) Slog.d(TAG, "getConfigurationIntent() returning config intent "
8658                            + intent);
8659                    return intent;
8660                } catch (RemoteException e) {
8661                    /* fall through to return null */
8662                }
8663            }
8664        }
8665
8666        return null;
8667    }
8668
8669    // Supply the configuration summary string for the given transport.  If the name is
8670    // not one of the available transports, or if the transport does not supply any
8671    // summary / destination string, the method can return null.
8672    //
8673    // This string is used VERBATIM as the summary text of the relevant Settings item!
8674    public String getDestinationString(String transportName) {
8675        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
8676                "getDestinationString");
8677
8678        synchronized (mTransports) {
8679            final IBackupTransport transport = mTransports.get(transportName);
8680            if (transport != null) {
8681                try {
8682                    final String text = transport.currentDestinationString();
8683                    if (MORE_DEBUG) Slog.d(TAG, "getDestinationString() returning " + text);
8684                    return text;
8685                } catch (RemoteException e) {
8686                    /* fall through to return null */
8687                }
8688            }
8689        }
8690
8691        return null;
8692    }
8693
8694    // Supply the manage-data intent for the given transport.
8695    public Intent getDataManagementIntent(String transportName) {
8696        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
8697                "getDataManagementIntent");
8698
8699        synchronized (mTransports) {
8700            final IBackupTransport transport = mTransports.get(transportName);
8701            if (transport != null) {
8702                try {
8703                    final Intent intent = transport.dataManagementIntent();
8704                    if (MORE_DEBUG) Slog.d(TAG, "getDataManagementIntent() returning intent "
8705                            + intent);
8706                    return intent;
8707                } catch (RemoteException e) {
8708                    /* fall through to return null */
8709                }
8710            }
8711        }
8712
8713        return null;
8714    }
8715
8716    // Supply the menu label for affordances that fire the manage-data intent
8717    // for the given transport.
8718    public String getDataManagementLabel(String transportName) {
8719        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
8720                "getDataManagementLabel");
8721
8722        synchronized (mTransports) {
8723            final IBackupTransport transport = mTransports.get(transportName);
8724            if (transport != null) {
8725                try {
8726                    final String text = transport.dataManagementLabel();
8727                    if (MORE_DEBUG) Slog.d(TAG, "getDataManagementLabel() returning " + text);
8728                    return text;
8729                } catch (RemoteException e) {
8730                    /* fall through to return null */
8731                }
8732            }
8733        }
8734
8735        return null;
8736    }
8737
8738    // Callback: a requested backup agent has been instantiated.  This should only
8739    // be called from the Activity Manager.
8740    public void agentConnected(String packageName, IBinder agentBinder) {
8741        synchronized(mAgentConnectLock) {
8742            if (Binder.getCallingUid() == Process.SYSTEM_UID) {
8743                Slog.d(TAG, "agentConnected pkg=" + packageName + " agent=" + agentBinder);
8744                IBackupAgent agent = IBackupAgent.Stub.asInterface(agentBinder);
8745                mConnectedAgent = agent;
8746                mConnecting = false;
8747            } else {
8748                Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
8749                        + " claiming agent connected");
8750            }
8751            mAgentConnectLock.notifyAll();
8752        }
8753    }
8754
8755    // Callback: a backup agent has failed to come up, or has unexpectedly quit.
8756    // If the agent failed to come up in the first place, the agentBinder argument
8757    // will be null.  This should only be called from the Activity Manager.
8758    public void agentDisconnected(String packageName) {
8759        // TODO: handle backup being interrupted
8760        synchronized(mAgentConnectLock) {
8761            if (Binder.getCallingUid() == Process.SYSTEM_UID) {
8762                mConnectedAgent = null;
8763                mConnecting = false;
8764            } else {
8765                Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
8766                        + " claiming agent disconnected");
8767            }
8768            mAgentConnectLock.notifyAll();
8769        }
8770    }
8771
8772    // An application being installed will need a restore pass, then the Package Manager
8773    // will need to be told when the restore is finished.
8774    public void restoreAtInstall(String packageName, int token) {
8775        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
8776            Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
8777                    + " attemping install-time restore");
8778            return;
8779        }
8780
8781        boolean skip = false;
8782
8783        long restoreSet = getAvailableRestoreToken(packageName);
8784        if (DEBUG) Slog.v(TAG, "restoreAtInstall pkg=" + packageName
8785                + " token=" + Integer.toHexString(token)
8786                + " restoreSet=" + Long.toHexString(restoreSet));
8787        if (restoreSet == 0) {
8788            if (MORE_DEBUG) Slog.i(TAG, "No restore set");
8789            skip = true;
8790        }
8791
8792        // Do we have a transport to fetch data for us?
8793        IBackupTransport transport = getTransport(mCurrentTransport);
8794        if (transport == null) {
8795            if (DEBUG) Slog.w(TAG, "No transport");
8796            skip = true;
8797        }
8798
8799        if (!mAutoRestore) {
8800            if (DEBUG) {
8801                Slog.w(TAG, "Non-restorable state: auto=" + mAutoRestore);
8802            }
8803            skip = true;
8804        }
8805
8806        if (!skip) {
8807            try {
8808                // okay, we're going to attempt a restore of this package from this restore set.
8809                // The eventual message back into the Package Manager to run the post-install
8810                // steps for 'token' will be issued from the restore handling code.
8811
8812                // This can throw and so *must* happen before the wakelock is acquired
8813                String dirName = transport.transportDirName();
8814
8815                // We can use a synthetic PackageInfo here because:
8816                //   1. We know it's valid, since the Package Manager supplied the name
8817                //   2. Only the packageName field will be used by the restore code
8818                PackageInfo pkg = new PackageInfo();
8819                pkg.packageName = packageName;
8820
8821                mWakelock.acquire();
8822                if (MORE_DEBUG) {
8823                    Slog.d(TAG, "Restore at install of " + packageName);
8824                }
8825                Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
8826                msg.obj = new RestoreParams(transport, dirName, null,
8827                        restoreSet, pkg, token);
8828                mBackupHandler.sendMessage(msg);
8829            } catch (RemoteException e) {
8830                // Binding to the transport broke; back off and proceed with the installation.
8831                Slog.e(TAG, "Unable to contact transport");
8832                skip = true;
8833            }
8834        }
8835
8836        if (skip) {
8837            // Auto-restore disabled or no way to attempt a restore; just tell the Package
8838            // Manager to proceed with the post-install handling for this package.
8839            if (DEBUG) Slog.v(TAG, "Finishing install immediately");
8840            try {
8841                mPackageManagerBinder.finishPackageInstall(token);
8842            } catch (RemoteException e) { /* can't happen */ }
8843        }
8844    }
8845
8846    // Hand off a restore session
8847    public IRestoreSession beginRestoreSession(String packageName, String transport) {
8848        if (DEBUG) Slog.v(TAG, "beginRestoreSession: pkg=" + packageName
8849                + " transport=" + transport);
8850
8851        boolean needPermission = true;
8852        if (transport == null) {
8853            transport = mCurrentTransport;
8854
8855            if (packageName != null) {
8856                PackageInfo app = null;
8857                try {
8858                    app = mPackageManager.getPackageInfo(packageName, 0);
8859                } catch (NameNotFoundException nnf) {
8860                    Slog.w(TAG, "Asked to restore nonexistent pkg " + packageName);
8861                    throw new IllegalArgumentException("Package " + packageName + " not found");
8862                }
8863
8864                if (app.applicationInfo.uid == Binder.getCallingUid()) {
8865                    // So: using the current active transport, and the caller has asked
8866                    // that its own package will be restored.  In this narrow use case
8867                    // we do not require the caller to hold the permission.
8868                    needPermission = false;
8869                }
8870            }
8871        }
8872
8873        if (needPermission) {
8874            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
8875                    "beginRestoreSession");
8876        } else {
8877            if (DEBUG) Slog.d(TAG, "restoring self on current transport; no permission needed");
8878        }
8879
8880        synchronized(this) {
8881            if (mActiveRestoreSession != null) {
8882                Slog.d(TAG, "Restore session requested but one already active");
8883                return null;
8884            }
8885            mActiveRestoreSession = new ActiveRestoreSession(packageName, transport);
8886            mBackupHandler.sendEmptyMessageDelayed(MSG_RESTORE_TIMEOUT, TIMEOUT_RESTORE_INTERVAL);
8887        }
8888        return mActiveRestoreSession;
8889    }
8890
8891    void clearRestoreSession(ActiveRestoreSession currentSession) {
8892        synchronized(this) {
8893            if (currentSession != mActiveRestoreSession) {
8894                Slog.e(TAG, "ending non-current restore session");
8895            } else {
8896                if (DEBUG) Slog.v(TAG, "Clearing restore session and halting timeout");
8897                mActiveRestoreSession = null;
8898                mBackupHandler.removeMessages(MSG_RESTORE_TIMEOUT);
8899            }
8900        }
8901    }
8902
8903    // Note that a currently-active backup agent has notified us that it has
8904    // completed the given outstanding asynchronous backup/restore operation.
8905    public void opComplete(int token) {
8906        if (MORE_DEBUG) Slog.v(TAG, "opComplete: " + Integer.toHexString(token));
8907        Operation op = null;
8908        synchronized (mCurrentOpLock) {
8909            op = mCurrentOperations.get(token);
8910            if (op != null) {
8911                op.state = OP_ACKNOWLEDGED;
8912            }
8913            mCurrentOpLock.notifyAll();
8914        }
8915
8916        // The completion callback, if any, is invoked on the handler
8917        if (op != null && op.callback != null) {
8918            Message msg = mBackupHandler.obtainMessage(MSG_OP_COMPLETE, op.callback);
8919            mBackupHandler.sendMessage(msg);
8920        }
8921    }
8922
8923    // ----- Restore session -----
8924
8925    class ActiveRestoreSession extends IRestoreSession.Stub {
8926        private static final String TAG = "RestoreSession";
8927
8928        private String mPackageName;
8929        private IBackupTransport mRestoreTransport = null;
8930        RestoreSet[] mRestoreSets = null;
8931        boolean mEnded = false;
8932        boolean mTimedOut = false;
8933
8934        ActiveRestoreSession(String packageName, String transport) {
8935            mPackageName = packageName;
8936            mRestoreTransport = getTransport(transport);
8937        }
8938
8939        public void markTimedOut() {
8940            mTimedOut = true;
8941        }
8942
8943        // --- Binder interface ---
8944        public synchronized int getAvailableRestoreSets(IRestoreObserver observer) {
8945            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
8946                    "getAvailableRestoreSets");
8947            if (observer == null) {
8948                throw new IllegalArgumentException("Observer must not be null");
8949            }
8950
8951            if (mEnded) {
8952                throw new IllegalStateException("Restore session already ended");
8953            }
8954
8955            if (mTimedOut) {
8956                Slog.i(TAG, "Session already timed out");
8957                return -1;
8958            }
8959
8960            long oldId = Binder.clearCallingIdentity();
8961            try {
8962                if (mRestoreTransport == null) {
8963                    Slog.w(TAG, "Null transport getting restore sets");
8964                    return -1;
8965                }
8966
8967                // We know we're doing legit work now, so halt the timeout
8968                // until we're done.  It gets started again when the result
8969                // comes in.
8970                mBackupHandler.removeMessages(MSG_RESTORE_TIMEOUT);
8971
8972                // spin off the transport request to our service thread
8973                mWakelock.acquire();
8974                Message msg = mBackupHandler.obtainMessage(MSG_RUN_GET_RESTORE_SETS,
8975                        new RestoreGetSetsParams(mRestoreTransport, this, observer));
8976                mBackupHandler.sendMessage(msg);
8977                return 0;
8978            } catch (Exception e) {
8979                Slog.e(TAG, "Error in getAvailableRestoreSets", e);
8980                return -1;
8981            } finally {
8982                Binder.restoreCallingIdentity(oldId);
8983            }
8984        }
8985
8986        public synchronized int restoreAll(long token, IRestoreObserver observer) {
8987            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
8988                    "performRestore");
8989
8990            if (DEBUG) Slog.d(TAG, "restoreAll token=" + Long.toHexString(token)
8991                    + " observer=" + observer);
8992
8993            if (mEnded) {
8994                throw new IllegalStateException("Restore session already ended");
8995            }
8996
8997            if (mTimedOut) {
8998                Slog.i(TAG, "Session already timed out");
8999                return -1;
9000            }
9001
9002            if (mRestoreTransport == null || mRestoreSets == null) {
9003                Slog.e(TAG, "Ignoring restoreAll() with no restore set");
9004                return -1;
9005            }
9006
9007            if (mPackageName != null) {
9008                Slog.e(TAG, "Ignoring restoreAll() on single-package session");
9009                return -1;
9010            }
9011
9012            String dirName;
9013            try {
9014                dirName = mRestoreTransport.transportDirName();
9015            } catch (RemoteException e) {
9016                // Transport went AWOL; fail.
9017                Slog.e(TAG, "Unable to contact transport for restore");
9018                return -1;
9019            }
9020
9021            synchronized (mQueueLock) {
9022                for (int i = 0; i < mRestoreSets.length; i++) {
9023                    if (token == mRestoreSets[i].token) {
9024                        // Real work, so stop the session timeout until we finalize the restore
9025                        mBackupHandler.removeMessages(MSG_RESTORE_TIMEOUT);
9026
9027                        long oldId = Binder.clearCallingIdentity();
9028                        mWakelock.acquire();
9029                        if (MORE_DEBUG) {
9030                            Slog.d(TAG, "restoreAll() kicking off");
9031                        }
9032                        Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
9033                        msg.obj = new RestoreParams(mRestoreTransport, dirName,
9034                                observer, token);
9035                        mBackupHandler.sendMessage(msg);
9036                        Binder.restoreCallingIdentity(oldId);
9037                        return 0;
9038                    }
9039                }
9040            }
9041
9042            Slog.w(TAG, "Restore token " + Long.toHexString(token) + " not found");
9043            return -1;
9044        }
9045
9046        // Restores of more than a single package are treated as 'system' restores
9047        public synchronized int restoreSome(long token, IRestoreObserver observer,
9048                String[] packages) {
9049            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
9050                    "performRestore");
9051
9052            if (DEBUG) {
9053                StringBuilder b = new StringBuilder(128);
9054                b.append("restoreSome token=");
9055                b.append(Long.toHexString(token));
9056                b.append(" observer=");
9057                b.append(observer.toString());
9058                b.append(" packages=");
9059                if (packages == null) {
9060                    b.append("null");
9061                } else {
9062                    b.append('{');
9063                    boolean first = true;
9064                    for (String s : packages) {
9065                        if (!first) {
9066                            b.append(", ");
9067                        } else first = false;
9068                        b.append(s);
9069                    }
9070                    b.append('}');
9071                }
9072                Slog.d(TAG, b.toString());
9073            }
9074
9075            if (mEnded) {
9076                throw new IllegalStateException("Restore session already ended");
9077            }
9078
9079            if (mTimedOut) {
9080                Slog.i(TAG, "Session already timed out");
9081                return -1;
9082            }
9083
9084            if (mRestoreTransport == null || mRestoreSets == null) {
9085                Slog.e(TAG, "Ignoring restoreAll() with no restore set");
9086                return -1;
9087            }
9088
9089            if (mPackageName != null) {
9090                Slog.e(TAG, "Ignoring restoreAll() on single-package session");
9091                return -1;
9092            }
9093
9094            String dirName;
9095            try {
9096                dirName = mRestoreTransport.transportDirName();
9097            } catch (RemoteException e) {
9098                // Transport went AWOL; fail.
9099                Slog.e(TAG, "Unable to contact transport for restore");
9100                return -1;
9101            }
9102
9103            synchronized (mQueueLock) {
9104                for (int i = 0; i < mRestoreSets.length; i++) {
9105                    if (token == mRestoreSets[i].token) {
9106                        // Stop the session timeout until we finalize the restore
9107                        mBackupHandler.removeMessages(MSG_RESTORE_TIMEOUT);
9108
9109                        long oldId = Binder.clearCallingIdentity();
9110                        mWakelock.acquire();
9111                        if (MORE_DEBUG) {
9112                            Slog.d(TAG, "restoreSome() of " + packages.length + " packages");
9113                        }
9114                        Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
9115                        msg.obj = new RestoreParams(mRestoreTransport, dirName, observer, token,
9116                                packages, packages.length > 1);
9117                        mBackupHandler.sendMessage(msg);
9118                        Binder.restoreCallingIdentity(oldId);
9119                        return 0;
9120                    }
9121                }
9122            }
9123
9124            Slog.w(TAG, "Restore token " + Long.toHexString(token) + " not found");
9125            return -1;
9126        }
9127
9128        public synchronized int restorePackage(String packageName, IRestoreObserver observer) {
9129            if (DEBUG) Slog.v(TAG, "restorePackage pkg=" + packageName + " obs=" + observer);
9130
9131            if (mEnded) {
9132                throw new IllegalStateException("Restore session already ended");
9133            }
9134
9135            if (mTimedOut) {
9136                Slog.i(TAG, "Session already timed out");
9137                return -1;
9138            }
9139
9140            if (mPackageName != null) {
9141                if (! mPackageName.equals(packageName)) {
9142                    Slog.e(TAG, "Ignoring attempt to restore pkg=" + packageName
9143                            + " on session for package " + mPackageName);
9144                    return -1;
9145                }
9146            }
9147
9148            PackageInfo app = null;
9149            try {
9150                app = mPackageManager.getPackageInfo(packageName, 0);
9151            } catch (NameNotFoundException nnf) {
9152                Slog.w(TAG, "Asked to restore nonexistent pkg " + packageName);
9153                return -1;
9154            }
9155
9156            // If the caller is not privileged and is not coming from the target
9157            // app's uid, throw a permission exception back to the caller.
9158            int perm = mContext.checkPermission(android.Manifest.permission.BACKUP,
9159                    Binder.getCallingPid(), Binder.getCallingUid());
9160            if ((perm == PackageManager.PERMISSION_DENIED) &&
9161                    (app.applicationInfo.uid != Binder.getCallingUid())) {
9162                Slog.w(TAG, "restorePackage: bad packageName=" + packageName
9163                        + " or calling uid=" + Binder.getCallingUid());
9164                throw new SecurityException("No permission to restore other packages");
9165            }
9166
9167            // So far so good; we're allowed to try to restore this package.  Now
9168            // check whether there is data for it in the current dataset, falling back
9169            // to the ancestral dataset if not.
9170            long token = getAvailableRestoreToken(packageName);
9171
9172            // If we didn't come up with a place to look -- no ancestral dataset and
9173            // the app has never been backed up from this device -- there's nothing
9174            // to do but return failure.
9175            if (token == 0) {
9176                if (DEBUG) Slog.w(TAG, "No data available for this package; not restoring");
9177                return -1;
9178            }
9179
9180            String dirName;
9181            try {
9182                dirName = mRestoreTransport.transportDirName();
9183            } catch (RemoteException e) {
9184                // Transport went AWOL; fail.
9185                Slog.e(TAG, "Unable to contact transport for restore");
9186                return -1;
9187            }
9188
9189            // Stop the session timeout until we finalize the restore
9190            mBackupHandler.removeMessages(MSG_RESTORE_TIMEOUT);
9191
9192            // Ready to go:  enqueue the restore request and claim success
9193            long oldId = Binder.clearCallingIdentity();
9194            mWakelock.acquire();
9195            if (MORE_DEBUG) {
9196                Slog.d(TAG, "restorePackage() : " + packageName);
9197            }
9198            Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
9199            msg.obj = new RestoreParams(mRestoreTransport, dirName,
9200                    observer, token, app, 0);
9201            mBackupHandler.sendMessage(msg);
9202            Binder.restoreCallingIdentity(oldId);
9203            return 0;
9204        }
9205
9206        // Posted to the handler to tear down a restore session in a cleanly synchronized way
9207        class EndRestoreRunnable implements Runnable {
9208            BackupManagerService mBackupManager;
9209            ActiveRestoreSession mSession;
9210
9211            EndRestoreRunnable(BackupManagerService manager, ActiveRestoreSession session) {
9212                mBackupManager = manager;
9213                mSession = session;
9214            }
9215
9216            public void run() {
9217                // clean up the session's bookkeeping
9218                synchronized (mSession) {
9219                    try {
9220                        if (mSession.mRestoreTransport != null) {
9221                            mSession.mRestoreTransport.finishRestore();
9222                        }
9223                    } catch (Exception e) {
9224                        Slog.e(TAG, "Error in finishRestore", e);
9225                    } finally {
9226                        mSession.mRestoreTransport = null;
9227                        mSession.mEnded = true;
9228                    }
9229                }
9230
9231                // clean up the BackupManagerImpl side of the bookkeeping
9232                // and cancel any pending timeout message
9233                mBackupManager.clearRestoreSession(mSession);
9234            }
9235        }
9236
9237        public synchronized void endRestoreSession() {
9238            if (DEBUG) Slog.d(TAG, "endRestoreSession");
9239
9240            if (mTimedOut) {
9241                Slog.i(TAG, "Session already timed out");
9242                return;
9243            }
9244
9245            if (mEnded) {
9246                throw new IllegalStateException("Restore session already ended");
9247            }
9248
9249            mBackupHandler.post(new EndRestoreRunnable(BackupManagerService.this, this));
9250        }
9251    }
9252
9253    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
9254        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
9255
9256        long identityToken = Binder.clearCallingIdentity();
9257        try {
9258            if (args != null) {
9259                for (String arg : args) {
9260                    if ("-h".equals(arg)) {
9261                        pw.println("'dumpsys backup' optional arguments:");
9262                        pw.println("  -h       : this help text");
9263                        pw.println("  a[gents] : dump information about defined backup agents");
9264                        return;
9265                    } else if ("agents".startsWith(arg)) {
9266                        dumpAgents(pw);
9267                        return;
9268                    }
9269                }
9270            }
9271            dumpInternal(pw);
9272        } finally {
9273            Binder.restoreCallingIdentity(identityToken);
9274        }
9275    }
9276
9277    private void dumpAgents(PrintWriter pw) {
9278        List<PackageInfo> agentPackages = allAgentPackages();
9279        pw.println("Defined backup agents:");
9280        for (PackageInfo pkg : agentPackages) {
9281            pw.print("  ");
9282            pw.print(pkg.packageName); pw.println(':');
9283            pw.print("      "); pw.println(pkg.applicationInfo.backupAgentName);
9284        }
9285    }
9286
9287    private void dumpInternal(PrintWriter pw) {
9288        synchronized (mQueueLock) {
9289            pw.println("Backup Manager is " + (mEnabled ? "enabled" : "disabled")
9290                    + " / " + (!mProvisioned ? "not " : "") + "provisioned / "
9291                    + (this.mPendingInits.size() == 0 ? "not " : "") + "pending init");
9292            pw.println("Auto-restore is " + (mAutoRestore ? "enabled" : "disabled"));
9293            if (mBackupRunning) pw.println("Backup currently running");
9294            pw.println("Last backup pass started: " + mLastBackupPass
9295                    + " (now = " + System.currentTimeMillis() + ')');
9296            pw.println("  next scheduled: " + mNextBackupPass);
9297
9298            pw.println("Available transports:");
9299            final String[] transports = listAllTransports();
9300            if (transports != null) {
9301                for (String t : listAllTransports()) {
9302                    pw.println((t.equals(mCurrentTransport) ? "  * " : "    ") + t);
9303                    try {
9304                        IBackupTransport transport = getTransport(t);
9305                        File dir = new File(mBaseStateDir, transport.transportDirName());
9306                        pw.println("       destination: " + transport.currentDestinationString());
9307                        pw.println("       intent: " + transport.configurationIntent());
9308                        for (File f : dir.listFiles()) {
9309                            pw.println("       " + f.getName() + " - " + f.length() + " state bytes");
9310                        }
9311                    } catch (Exception e) {
9312                        Slog.e(TAG, "Error in transport", e);
9313                        pw.println("        Error: " + e);
9314                    }
9315                }
9316            }
9317
9318            pw.println("Pending init: " + mPendingInits.size());
9319            for (String s : mPendingInits) {
9320                pw.println("    " + s);
9321            }
9322
9323            if (DEBUG_BACKUP_TRACE) {
9324                synchronized (mBackupTrace) {
9325                    if (!mBackupTrace.isEmpty()) {
9326                        pw.println("Most recent backup trace:");
9327                        for (String s : mBackupTrace) {
9328                            pw.println("   " + s);
9329                        }
9330                    }
9331                }
9332            }
9333
9334            int N = mBackupParticipants.size();
9335            pw.println("Participants:");
9336            for (int i=0; i<N; i++) {
9337                int uid = mBackupParticipants.keyAt(i);
9338                pw.print("  uid: ");
9339                pw.println(uid);
9340                HashSet<String> participants = mBackupParticipants.valueAt(i);
9341                for (String app: participants) {
9342                    pw.println("    " + app);
9343                }
9344            }
9345
9346            pw.println("Ancestral packages: "
9347                    + (mAncestralPackages == null ? "none" : mAncestralPackages.size()));
9348            if (mAncestralPackages != null) {
9349                for (String pkg : mAncestralPackages) {
9350                    pw.println("    " + pkg);
9351                }
9352            }
9353
9354            pw.println("Ever backed up: " + mEverStoredApps.size());
9355            for (String pkg : mEverStoredApps) {
9356                pw.println("    " + pkg);
9357            }
9358
9359            pw.println("Pending key/value backup: " + mPendingBackups.size());
9360            for (BackupRequest req : mPendingBackups.values()) {
9361                pw.println("    " + req);
9362            }
9363
9364            pw.println("Full backup queue:" + mFullBackupQueue.size());
9365            for (FullBackupEntry entry : mFullBackupQueue) {
9366                pw.print("    "); pw.print(entry.lastBackup);
9367                pw.print(" : "); pw.println(entry.packageName);
9368            }
9369        }
9370    }
9371}
9372