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