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