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