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