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