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