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