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