Home | History | Annotate | Download | only in server
      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 
     17 package com.android.server;
     18 
     19 import android.app.ActivityManagerNative;
     20 import android.app.AlarmManager;
     21 import android.app.AppGlobals;
     22 import android.app.IActivityManager;
     23 import android.app.IApplicationThread;
     24 import android.app.IBackupAgent;
     25 import android.app.PendingIntent;
     26 import android.app.backup.RestoreSet;
     27 import android.app.backup.IBackupManager;
     28 import android.app.backup.IRestoreObserver;
     29 import android.app.backup.IRestoreSession;
     30 import android.content.BroadcastReceiver;
     31 import android.content.ComponentName;
     32 import android.content.Context;
     33 import android.content.Intent;
     34 import android.content.IntentFilter;
     35 import android.content.ServiceConnection;
     36 import android.content.pm.ApplicationInfo;
     37 import android.content.pm.IPackageDataObserver;
     38 import android.content.pm.IPackageManager;
     39 import android.content.pm.PackageInfo;
     40 import android.content.pm.PackageManager;
     41 import android.content.pm.Signature;
     42 import android.content.pm.PackageManager.NameNotFoundException;
     43 import android.net.Uri;
     44 import android.os.Binder;
     45 import android.os.Bundle;
     46 import android.os.Environment;
     47 import android.os.Handler;
     48 import android.os.HandlerThread;
     49 import android.os.IBinder;
     50 import android.os.Looper;
     51 import android.os.Message;
     52 import android.os.ParcelFileDescriptor;
     53 import android.os.PowerManager;
     54 import android.os.Process;
     55 import android.os.RemoteException;
     56 import android.os.SystemClock;
     57 import android.os.WorkSource;
     58 import android.provider.Settings;
     59 import android.util.EventLog;
     60 import android.util.Slog;
     61 import android.util.SparseArray;
     62 import android.util.SparseIntArray;
     63 
     64 import com.android.internal.backup.BackupConstants;
     65 import com.android.internal.backup.IBackupTransport;
     66 import com.android.internal.backup.LocalTransport;
     67 import com.android.server.PackageManagerBackupAgent.Metadata;
     68 
     69 import java.io.EOFException;
     70 import java.io.File;
     71 import java.io.FileDescriptor;
     72 import java.io.FileNotFoundException;
     73 import java.io.FileOutputStream;
     74 import java.io.IOException;
     75 import java.io.PrintWriter;
     76 import java.io.RandomAccessFile;
     77 import java.util.ArrayList;
     78 import java.util.HashMap;
     79 import java.util.HashSet;
     80 import java.util.List;
     81 import java.util.Map;
     82 import java.util.Random;
     83 import java.util.Set;
     84 
     85 class BackupManagerService extends IBackupManager.Stub {
     86     private static final String TAG = "BackupManagerService";
     87     private static final boolean DEBUG = false;
     88 
     89     // How often we perform a backup pass.  Privileged external callers can
     90     // trigger an immediate pass.
     91     private static final long BACKUP_INTERVAL = AlarmManager.INTERVAL_HOUR;
     92 
     93     // Random variation in backup scheduling time to avoid server load spikes
     94     private static final int FUZZ_MILLIS = 5 * 60 * 1000;
     95 
     96     // The amount of time between the initial provisioning of the device and
     97     // the first backup pass.
     98     private static final long FIRST_BACKUP_INTERVAL = 12 * AlarmManager.INTERVAL_HOUR;
     99 
    100     private static final String RUN_BACKUP_ACTION = "android.app.backup.intent.RUN";
    101     private static final String RUN_INITIALIZE_ACTION = "android.app.backup.intent.INIT";
    102     private static final String RUN_CLEAR_ACTION = "android.app.backup.intent.CLEAR";
    103     private static final int MSG_RUN_BACKUP = 1;
    104     private static final int MSG_RUN_FULL_BACKUP = 2;
    105     private static final int MSG_RUN_RESTORE = 3;
    106     private static final int MSG_RUN_CLEAR = 4;
    107     private static final int MSG_RUN_INITIALIZE = 5;
    108     private static final int MSG_RUN_GET_RESTORE_SETS = 6;
    109     private static final int MSG_TIMEOUT = 7;
    110 
    111     // Timeout interval for deciding that a bind or clear-data has taken too long
    112     static final long TIMEOUT_INTERVAL = 10 * 1000;
    113 
    114     // Timeout intervals for agent backup & restore operations
    115     static final long TIMEOUT_BACKUP_INTERVAL = 30 * 1000;
    116     static final long TIMEOUT_RESTORE_INTERVAL = 60 * 1000;
    117 
    118     private Context mContext;
    119     private PackageManager mPackageManager;
    120     IPackageManager mPackageManagerBinder;
    121     private IActivityManager mActivityManager;
    122     private PowerManager mPowerManager;
    123     private AlarmManager mAlarmManager;
    124     IBackupManager mBackupManagerBinder;
    125 
    126     boolean mEnabled;   // access to this is synchronized on 'this'
    127     boolean mProvisioned;
    128     boolean mAutoRestore;
    129     PowerManager.WakeLock mWakelock;
    130     HandlerThread mHandlerThread = new HandlerThread("backup", Process.THREAD_PRIORITY_BACKGROUND);
    131     BackupHandler mBackupHandler;
    132     PendingIntent mRunBackupIntent, mRunInitIntent;
    133     BroadcastReceiver mRunBackupReceiver, mRunInitReceiver;
    134     // map UIDs to the set of backup client services within that UID's app set
    135     final SparseArray<HashSet<ApplicationInfo>> mBackupParticipants
    136         = new SparseArray<HashSet<ApplicationInfo>>();
    137     // set of backup services that have pending changes
    138     class BackupRequest {
    139         public ApplicationInfo appInfo;
    140         public boolean fullBackup;
    141 
    142         BackupRequest(ApplicationInfo app, boolean isFull) {
    143             appInfo = app;
    144             fullBackup = isFull;
    145         }
    146 
    147         public String toString() {
    148             return "BackupRequest{app=" + appInfo + " full=" + fullBackup + "}";
    149         }
    150     }
    151     // Backups that we haven't started yet.
    152     HashMap<ApplicationInfo,BackupRequest> mPendingBackups
    153             = new HashMap<ApplicationInfo,BackupRequest>();
    154 
    155     // Pseudoname that we use for the Package Manager metadata "package"
    156     static final String PACKAGE_MANAGER_SENTINEL = "@pm@";
    157 
    158     // locking around the pending-backup management
    159     final Object mQueueLock = new Object();
    160 
    161     // The thread performing the sequence of queued backups binds to each app's agent
    162     // in succession.  Bind notifications are asynchronously delivered through the
    163     // Activity Manager; use this lock object to signal when a requested binding has
    164     // completed.
    165     final Object mAgentConnectLock = new Object();
    166     IBackupAgent mConnectedAgent;
    167     volatile boolean mConnecting;
    168     volatile long mLastBackupPass;
    169     volatile long mNextBackupPass;
    170 
    171     // A similar synchronization mechanism around clearing apps' data for restore
    172     final Object mClearDataLock = new Object();
    173     volatile boolean mClearingData;
    174 
    175     // Transport bookkeeping
    176     final HashMap<String,IBackupTransport> mTransports
    177             = new HashMap<String,IBackupTransport>();
    178     String mCurrentTransport;
    179     IBackupTransport mLocalTransport, mGoogleTransport;
    180     ActiveRestoreSession mActiveRestoreSession;
    181 
    182     class RestoreGetSetsParams {
    183         public IBackupTransport transport;
    184         public ActiveRestoreSession session;
    185         public IRestoreObserver observer;
    186 
    187         RestoreGetSetsParams(IBackupTransport _transport, ActiveRestoreSession _session,
    188                 IRestoreObserver _observer) {
    189             transport = _transport;
    190             session = _session;
    191             observer = _observer;
    192         }
    193     }
    194 
    195     class RestoreParams {
    196         public IBackupTransport transport;
    197         public IRestoreObserver observer;
    198         public long token;
    199         public PackageInfo pkgInfo;
    200         public int pmToken; // in post-install restore, the PM's token for this transaction
    201         public boolean needFullBackup;
    202 
    203         RestoreParams(IBackupTransport _transport, IRestoreObserver _obs,
    204                 long _token, PackageInfo _pkg, int _pmToken, boolean _needFullBackup) {
    205             transport = _transport;
    206             observer = _obs;
    207             token = _token;
    208             pkgInfo = _pkg;
    209             pmToken = _pmToken;
    210             needFullBackup = _needFullBackup;
    211         }
    212 
    213         RestoreParams(IBackupTransport _transport, IRestoreObserver _obs, long _token,
    214                 boolean _needFullBackup) {
    215             transport = _transport;
    216             observer = _obs;
    217             token = _token;
    218             pkgInfo = null;
    219             pmToken = 0;
    220             needFullBackup = _needFullBackup;
    221         }
    222     }
    223 
    224     class ClearParams {
    225         public IBackupTransport transport;
    226         public PackageInfo packageInfo;
    227 
    228         ClearParams(IBackupTransport _transport, PackageInfo _info) {
    229             transport = _transport;
    230             packageInfo = _info;
    231         }
    232     }
    233 
    234     // Bookkeeping of in-flight operations for timeout etc. purposes.  The operation
    235     // token is the index of the entry in the pending-operations list.
    236     static final int OP_PENDING = 0;
    237     static final int OP_ACKNOWLEDGED = 1;
    238     static final int OP_TIMEOUT = -1;
    239 
    240     final SparseIntArray mCurrentOperations = new SparseIntArray();
    241     final Object mCurrentOpLock = new Object();
    242     final Random mTokenGenerator = new Random();
    243 
    244     // Where we keep our journal files and other bookkeeping
    245     File mBaseStateDir;
    246     File mDataDir;
    247     File mJournalDir;
    248     File mJournal;
    249 
    250     // Keep a log of all the apps we've ever backed up, and what the
    251     // dataset tokens are for both the current backup dataset and
    252     // the ancestral dataset.
    253     private File mEverStored;
    254     HashSet<String> mEverStoredApps = new HashSet<String>();
    255 
    256     static final int CURRENT_ANCESTRAL_RECORD_VERSION = 1;  // increment when the schema changes
    257     File mTokenFile;
    258     Set<String> mAncestralPackages = null;
    259     long mAncestralToken = 0;
    260     long mCurrentToken = 0;
    261 
    262     // Persistently track the need to do a full init
    263     static final String INIT_SENTINEL_FILE_NAME = "_need_init_";
    264     HashSet<String> mPendingInits = new HashSet<String>();  // transport names
    265 
    266     // ----- Asynchronous backup/restore handler thread -----
    267 
    268     private class BackupHandler extends Handler {
    269         public BackupHandler(Looper looper) {
    270             super(looper);
    271         }
    272 
    273         public void handleMessage(Message msg) {
    274 
    275             switch (msg.what) {
    276             case MSG_RUN_BACKUP:
    277             {
    278                 mLastBackupPass = System.currentTimeMillis();
    279                 mNextBackupPass = mLastBackupPass + BACKUP_INTERVAL;
    280 
    281                 IBackupTransport transport = getTransport(mCurrentTransport);
    282                 if (transport == null) {
    283                     Slog.v(TAG, "Backup requested but no transport available");
    284                     mWakelock.release();
    285                     break;
    286                 }
    287 
    288                 // snapshot the pending-backup set and work on that
    289                 ArrayList<BackupRequest> queue = new ArrayList<BackupRequest>();
    290                 File oldJournal = mJournal;
    291                 synchronized (mQueueLock) {
    292                     // Do we have any work to do?  Construct the work queue
    293                     // then release the synchronization lock to actually run
    294                     // the backup.
    295                     if (mPendingBackups.size() > 0) {
    296                         for (BackupRequest b: mPendingBackups.values()) {
    297                             queue.add(b);
    298                         }
    299                         if (DEBUG) Slog.v(TAG, "clearing pending backups");
    300                         mPendingBackups.clear();
    301 
    302                         // Start a new backup-queue journal file too
    303                         mJournal = null;
    304 
    305                     }
    306                 }
    307 
    308                 if (queue.size() > 0) {
    309                     // At this point, we have started a new journal file, and the old
    310                     // file identity is being passed to the backup processing thread.
    311                     // When it completes successfully, that old journal file will be
    312                     // deleted.  If we crash prior to that, the old journal is parsed
    313                     // at next boot and the journaled requests fulfilled.
    314                     (new PerformBackupTask(transport, queue, oldJournal)).run();
    315                 } else {
    316                     Slog.v(TAG, "Backup requested but nothing pending");
    317                     mWakelock.release();
    318                 }
    319                 break;
    320             }
    321 
    322             case MSG_RUN_FULL_BACKUP:
    323                 break;
    324 
    325             case MSG_RUN_RESTORE:
    326             {
    327                 RestoreParams params = (RestoreParams)msg.obj;
    328                 Slog.d(TAG, "MSG_RUN_RESTORE observer=" + params.observer);
    329                 (new PerformRestoreTask(params.transport, params.observer,
    330                         params.token, params.pkgInfo, params.pmToken,
    331                         params.needFullBackup)).run();
    332                 break;
    333             }
    334 
    335             case MSG_RUN_CLEAR:
    336             {
    337                 ClearParams params = (ClearParams)msg.obj;
    338                 (new PerformClearTask(params.transport, params.packageInfo)).run();
    339                 break;
    340             }
    341 
    342             case MSG_RUN_INITIALIZE:
    343             {
    344                 HashSet<String> queue;
    345 
    346                 // Snapshot the pending-init queue and work on that
    347                 synchronized (mQueueLock) {
    348                     queue = new HashSet<String>(mPendingInits);
    349                     mPendingInits.clear();
    350                 }
    351 
    352                 (new PerformInitializeTask(queue)).run();
    353                 break;
    354             }
    355 
    356             case MSG_RUN_GET_RESTORE_SETS:
    357             {
    358                 // Like other async operations, this is entered with the wakelock held
    359                 RestoreSet[] sets = null;
    360                 RestoreGetSetsParams params = (RestoreGetSetsParams)msg.obj;
    361                 try {
    362                     sets = params.transport.getAvailableRestoreSets();
    363                     // cache the result in the active session
    364                     synchronized (params.session) {
    365                         params.session.mRestoreSets = sets;
    366                     }
    367                     if (sets == null) EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
    368                 } catch (Exception e) {
    369                     Slog.e(TAG, "Error from transport getting set list");
    370                 } finally {
    371                     if (params.observer != null) {
    372                         try {
    373                             params.observer.restoreSetsAvailable(sets);
    374                         } catch (RemoteException re) {
    375                             Slog.e(TAG, "Unable to report listing to observer");
    376                         } catch (Exception e) {
    377                             Slog.e(TAG, "Restore observer threw", e);
    378                         }
    379                     }
    380 
    381                     mWakelock.release();
    382                 }
    383                 break;
    384             }
    385 
    386             case MSG_TIMEOUT:
    387             {
    388                 synchronized (mCurrentOpLock) {
    389                     final int token = msg.arg1;
    390                     int state = mCurrentOperations.get(token, OP_TIMEOUT);
    391                     if (state == OP_PENDING) {
    392                         if (DEBUG) Slog.v(TAG, "TIMEOUT: token=" + token);
    393                         mCurrentOperations.put(token, OP_TIMEOUT);
    394                     }
    395                     mCurrentOpLock.notifyAll();
    396                 }
    397                 break;
    398             }
    399             }
    400         }
    401     }
    402 
    403     // ----- Main service implementation -----
    404 
    405     public BackupManagerService(Context context) {
    406         mContext = context;
    407         mPackageManager = context.getPackageManager();
    408         mPackageManagerBinder = AppGlobals.getPackageManager();
    409         mActivityManager = ActivityManagerNative.getDefault();
    410 
    411         mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    412         mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
    413 
    414         mBackupManagerBinder = asInterface(asBinder());
    415 
    416         // spin up the backup/restore handler thread
    417         mHandlerThread = new HandlerThread("backup", Process.THREAD_PRIORITY_BACKGROUND);
    418         mHandlerThread.start();
    419         mBackupHandler = new BackupHandler(mHandlerThread.getLooper());
    420 
    421         // Set up our bookkeeping
    422         boolean areEnabled = Settings.Secure.getInt(context.getContentResolver(),
    423                 Settings.Secure.BACKUP_ENABLED, 0) != 0;
    424         mProvisioned = Settings.Secure.getInt(context.getContentResolver(),
    425                 Settings.Secure.BACKUP_PROVISIONED, 0) != 0;
    426         mAutoRestore = Settings.Secure.getInt(context.getContentResolver(),
    427                 Settings.Secure.BACKUP_AUTO_RESTORE, 1) != 0;
    428         // If Encrypted file systems is enabled or disabled, this call will return the
    429         // correct directory.
    430         mBaseStateDir = new File(Environment.getSecureDataDirectory(), "backup");
    431         mBaseStateDir.mkdirs();
    432         mDataDir = Environment.getDownloadCacheDirectory();
    433 
    434         // Alarm receivers for scheduled backups & initialization operations
    435         mRunBackupReceiver = new RunBackupReceiver();
    436         IntentFilter filter = new IntentFilter();
    437         filter.addAction(RUN_BACKUP_ACTION);
    438         context.registerReceiver(mRunBackupReceiver, filter,
    439                 android.Manifest.permission.BACKUP, null);
    440 
    441         mRunInitReceiver = new RunInitializeReceiver();
    442         filter = new IntentFilter();
    443         filter.addAction(RUN_INITIALIZE_ACTION);
    444         context.registerReceiver(mRunInitReceiver, filter,
    445                 android.Manifest.permission.BACKUP, null);
    446 
    447         Intent backupIntent = new Intent(RUN_BACKUP_ACTION);
    448         backupIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
    449         mRunBackupIntent = PendingIntent.getBroadcast(context, MSG_RUN_BACKUP, backupIntent, 0);
    450 
    451         Intent initIntent = new Intent(RUN_INITIALIZE_ACTION);
    452         backupIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
    453         mRunInitIntent = PendingIntent.getBroadcast(context, MSG_RUN_INITIALIZE, initIntent, 0);
    454 
    455         // Set up the backup-request journaling
    456         mJournalDir = new File(mBaseStateDir, "pending");
    457         mJournalDir.mkdirs();   // creates mBaseStateDir along the way
    458         mJournal = null;        // will be created on first use
    459 
    460         // Set up the various sorts of package tracking we do
    461         initPackageTracking();
    462 
    463         // Build our mapping of uid to backup client services.  This implicitly
    464         // schedules a backup pass on the Package Manager metadata the first
    465         // time anything needs to be backed up.
    466         synchronized (mBackupParticipants) {
    467             addPackageParticipantsLocked(null);
    468         }
    469 
    470         // Set up our transport options and initialize the default transport
    471         // TODO: Have transports register themselves somehow?
    472         // TODO: Don't create transports that we don't need to?
    473         mLocalTransport = new LocalTransport(context);  // This is actually pretty cheap
    474         ComponentName localName = new ComponentName(context, LocalTransport.class);
    475         registerTransport(localName.flattenToShortString(), mLocalTransport);
    476 
    477         mGoogleTransport = null;
    478         mCurrentTransport = Settings.Secure.getString(context.getContentResolver(),
    479                 Settings.Secure.BACKUP_TRANSPORT);
    480         if ("".equals(mCurrentTransport)) {
    481             mCurrentTransport = null;
    482         }
    483         if (DEBUG) Slog.v(TAG, "Starting with transport " + mCurrentTransport);
    484 
    485         // Attach to the Google backup transport.  When this comes up, it will set
    486         // itself as the current transport because we explicitly reset mCurrentTransport
    487         // to null.
    488         ComponentName transportComponent = new ComponentName("com.google.android.backup",
    489                 "com.google.android.backup.BackupTransportService");
    490         try {
    491             // If there's something out there that is supposed to be the Google
    492             // backup transport, make sure it's legitimately part of the OS build
    493             // and not an app lying about its package name.
    494             ApplicationInfo info = mPackageManager.getApplicationInfo(
    495                     transportComponent.getPackageName(), 0);
    496             if ((info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
    497                 if (DEBUG) Slog.v(TAG, "Binding to Google transport");
    498                 Intent intent = new Intent().setComponent(transportComponent);
    499                 context.bindService(intent, mGoogleConnection, Context.BIND_AUTO_CREATE);
    500             } else {
    501                 Slog.w(TAG, "Possible Google transport spoof: ignoring " + info);
    502             }
    503         } catch (PackageManager.NameNotFoundException nnf) {
    504             // No such package?  No binding.
    505             if (DEBUG) Slog.v(TAG, "Google transport not present");
    506         }
    507 
    508         // Now that we know about valid backup participants, parse any
    509         // leftover journal files into the pending backup set
    510         parseLeftoverJournals();
    511 
    512         // Power management
    513         mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*");
    514 
    515         // Start the backup passes going
    516         setBackupEnabled(areEnabled);
    517     }
    518 
    519     private class RunBackupReceiver extends BroadcastReceiver {
    520         public void onReceive(Context context, Intent intent) {
    521             if (RUN_BACKUP_ACTION.equals(intent.getAction())) {
    522                 synchronized (mQueueLock) {
    523                     if (mPendingInits.size() > 0) {
    524                         // If there are pending init operations, we process those
    525                         // and then settle into the usual periodic backup schedule.
    526                         if (DEBUG) Slog.v(TAG, "Init pending at scheduled backup");
    527                         try {
    528                             mAlarmManager.cancel(mRunInitIntent);
    529                             mRunInitIntent.send();
    530                         } catch (PendingIntent.CanceledException ce) {
    531                             Slog.e(TAG, "Run init intent cancelled");
    532                             // can't really do more than bail here
    533                         }
    534                     } else {
    535                         // Don't run backups now if we're disabled or not yet
    536                         // fully set up.
    537                         if (mEnabled && mProvisioned) {
    538                             if (DEBUG) Slog.v(TAG, "Running a backup pass");
    539 
    540                             // Acquire the wakelock and pass it to the backup thread.  it will
    541                             // be released once backup concludes.
    542                             mWakelock.acquire();
    543 
    544                             Message msg = mBackupHandler.obtainMessage(MSG_RUN_BACKUP);
    545                             mBackupHandler.sendMessage(msg);
    546                         } else {
    547                             Slog.w(TAG, "Backup pass but e=" + mEnabled + " p=" + mProvisioned);
    548                         }
    549                     }
    550                 }
    551             }
    552         }
    553     }
    554 
    555     private class RunInitializeReceiver extends BroadcastReceiver {
    556         public void onReceive(Context context, Intent intent) {
    557             if (RUN_INITIALIZE_ACTION.equals(intent.getAction())) {
    558                 synchronized (mQueueLock) {
    559                     if (DEBUG) Slog.v(TAG, "Running a device init");
    560 
    561                     // Acquire the wakelock and pass it to the init thread.  it will
    562                     // be released once init concludes.
    563                     mWakelock.acquire();
    564 
    565                     Message msg = mBackupHandler.obtainMessage(MSG_RUN_INITIALIZE);
    566                     mBackupHandler.sendMessage(msg);
    567                 }
    568             }
    569         }
    570     }
    571 
    572     private void initPackageTracking() {
    573         if (DEBUG) Slog.v(TAG, "Initializing package tracking");
    574 
    575         // Remember our ancestral dataset
    576         mTokenFile = new File(mBaseStateDir, "ancestral");
    577         try {
    578             RandomAccessFile tf = new RandomAccessFile(mTokenFile, "r");
    579             int version = tf.readInt();
    580             if (version == CURRENT_ANCESTRAL_RECORD_VERSION) {
    581                 mAncestralToken = tf.readLong();
    582                 mCurrentToken = tf.readLong();
    583 
    584                 int numPackages = tf.readInt();
    585                 if (numPackages >= 0) {
    586                     mAncestralPackages = new HashSet<String>();
    587                     for (int i = 0; i < numPackages; i++) {
    588                         String pkgName = tf.readUTF();
    589                         mAncestralPackages.add(pkgName);
    590                     }
    591                 }
    592             }
    593         } catch (FileNotFoundException fnf) {
    594             // Probably innocuous
    595             Slog.v(TAG, "No ancestral data");
    596         } catch (IOException e) {
    597             Slog.w(TAG, "Unable to read token file", e);
    598         }
    599 
    600         // Keep a log of what apps we've ever backed up.  Because we might have
    601         // rebooted in the middle of an operation that was removing something from
    602         // this log, we sanity-check its contents here and reconstruct it.
    603         mEverStored = new File(mBaseStateDir, "processed");
    604         File tempProcessedFile = new File(mBaseStateDir, "processed.new");
    605 
    606         // If we were in the middle of removing something from the ever-backed-up
    607         // file, there might be a transient "processed.new" file still present.
    608         // Ignore it -- we'll validate "processed" against the current package set.
    609         if (tempProcessedFile.exists()) {
    610             tempProcessedFile.delete();
    611         }
    612 
    613         // If there are previous contents, parse them out then start a new
    614         // file to continue the recordkeeping.
    615         if (mEverStored.exists()) {
    616             RandomAccessFile temp = null;
    617             RandomAccessFile in = null;
    618 
    619             try {
    620                 temp = new RandomAccessFile(tempProcessedFile, "rws");
    621                 in = new RandomAccessFile(mEverStored, "r");
    622 
    623                 while (true) {
    624                     PackageInfo info;
    625                     String pkg = in.readUTF();
    626                     try {
    627                         info = mPackageManager.getPackageInfo(pkg, 0);
    628                         mEverStoredApps.add(pkg);
    629                         temp.writeUTF(pkg);
    630                         if (DEBUG) Slog.v(TAG, "   + " + pkg);
    631                     } catch (NameNotFoundException e) {
    632                         // nope, this package was uninstalled; don't include it
    633                         if (DEBUG) Slog.v(TAG, "   - " + pkg);
    634                     }
    635                 }
    636             } catch (EOFException e) {
    637                 // Once we've rewritten the backup history log, atomically replace the
    638                 // old one with the new one then reopen the file for continuing use.
    639                 if (!tempProcessedFile.renameTo(mEverStored)) {
    640                     Slog.e(TAG, "Error renaming " + tempProcessedFile + " to " + mEverStored);
    641                 }
    642             } catch (IOException e) {
    643                 Slog.e(TAG, "Error in processed file", e);
    644             } finally {
    645                 try { if (temp != null) temp.close(); } catch (IOException e) {}
    646                 try { if (in != null) in.close(); } catch (IOException e) {}
    647             }
    648         }
    649 
    650         // Register for broadcasts about package install, etc., so we can
    651         // update the provider list.
    652         IntentFilter filter = new IntentFilter();
    653         filter.addAction(Intent.ACTION_PACKAGE_ADDED);
    654         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
    655         filter.addDataScheme("package");
    656         mContext.registerReceiver(mBroadcastReceiver, filter);
    657         // Register for events related to sdcard installation.
    658         IntentFilter sdFilter = new IntentFilter();
    659         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
    660         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
    661         mContext.registerReceiver(mBroadcastReceiver, sdFilter);
    662     }
    663 
    664     private void parseLeftoverJournals() {
    665         for (File f : mJournalDir.listFiles()) {
    666             if (mJournal == null || f.compareTo(mJournal) != 0) {
    667                 // This isn't the current journal, so it must be a leftover.  Read
    668                 // out the package names mentioned there and schedule them for
    669                 // backup.
    670                 RandomAccessFile in = null;
    671                 try {
    672                     Slog.i(TAG, "Found stale backup journal, scheduling");
    673                     in = new RandomAccessFile(f, "r");
    674                     while (true) {
    675                         String packageName = in.readUTF();
    676                         Slog.i(TAG, "  " + packageName);
    677                         dataChangedImpl(packageName);
    678                     }
    679                 } catch (EOFException e) {
    680                     // no more data; we're done
    681                 } catch (Exception e) {
    682                     Slog.e(TAG, "Can't read " + f, e);
    683                 } finally {
    684                     // close/delete the file
    685                     try { if (in != null) in.close(); } catch (IOException e) {}
    686                     f.delete();
    687                 }
    688             }
    689         }
    690     }
    691 
    692     // Maintain persistent state around whether need to do an initialize operation.
    693     // Must be called with the queue lock held.
    694     void recordInitPendingLocked(boolean isPending, String transportName) {
    695         if (DEBUG) Slog.i(TAG, "recordInitPendingLocked: " + isPending
    696                 + " on transport " + transportName);
    697         try {
    698             IBackupTransport transport = getTransport(transportName);
    699             String transportDirName = transport.transportDirName();
    700             File stateDir = new File(mBaseStateDir, transportDirName);
    701             File initPendingFile = new File(stateDir, INIT_SENTINEL_FILE_NAME);
    702 
    703             if (isPending) {
    704                 // We need an init before we can proceed with sending backup data.
    705                 // Record that with an entry in our set of pending inits, as well as
    706                 // journaling it via creation of a sentinel file.
    707                 mPendingInits.add(transportName);
    708                 try {
    709                     (new FileOutputStream(initPendingFile)).close();
    710                 } catch (IOException ioe) {
    711                     // Something is badly wrong with our permissions; just try to move on
    712                 }
    713             } else {
    714                 // No more initialization needed; wipe the journal and reset our state.
    715                 initPendingFile.delete();
    716                 mPendingInits.remove(transportName);
    717             }
    718         } catch (RemoteException e) {
    719             // can't happen; the transport is local
    720         }
    721     }
    722 
    723     // Reset all of our bookkeeping, in response to having been told that
    724     // the backend data has been wiped [due to idle expiry, for example],
    725     // so we must re-upload all saved settings.
    726     void resetBackupState(File stateFileDir) {
    727         synchronized (mQueueLock) {
    728             // Wipe the "what we've ever backed up" tracking
    729             mEverStoredApps.clear();
    730             mEverStored.delete();
    731 
    732             mCurrentToken = 0;
    733             writeRestoreTokens();
    734 
    735             // Remove all the state files
    736             for (File sf : stateFileDir.listFiles()) {
    737                 // ... but don't touch the needs-init sentinel
    738                 if (!sf.getName().equals(INIT_SENTINEL_FILE_NAME)) {
    739                     sf.delete();
    740                 }
    741             }
    742 
    743             // Enqueue a new backup of every participant
    744             int N = mBackupParticipants.size();
    745             for (int i=0; i<N; i++) {
    746                 int uid = mBackupParticipants.keyAt(i);
    747                 HashSet<ApplicationInfo> participants = mBackupParticipants.valueAt(i);
    748                 for (ApplicationInfo app: participants) {
    749                     dataChangedImpl(app.packageName);
    750                 }
    751             }
    752         }
    753     }
    754 
    755     // Add a transport to our set of available backends.  If 'transport' is null, this
    756     // is an unregistration, and the transport's entry is removed from our bookkeeping.
    757     private void registerTransport(String name, IBackupTransport transport) {
    758         synchronized (mTransports) {
    759             if (DEBUG) Slog.v(TAG, "Registering transport " + name + " = " + transport);
    760             if (transport != null) {
    761                 mTransports.put(name, transport);
    762             } else {
    763                 mTransports.remove(name);
    764                 if ((mCurrentTransport != null) && mCurrentTransport.equals(name)) {
    765                     mCurrentTransport = null;
    766                 }
    767                 // Nothing further to do in the unregistration case
    768                 return;
    769             }
    770         }
    771 
    772         // If the init sentinel file exists, we need to be sure to perform the init
    773         // as soon as practical.  We also create the state directory at registration
    774         // time to ensure it's present from the outset.
    775         try {
    776             String transportName = transport.transportDirName();
    777             File stateDir = new File(mBaseStateDir, transportName);
    778             stateDir.mkdirs();
    779 
    780             File initSentinel = new File(stateDir, INIT_SENTINEL_FILE_NAME);
    781             if (initSentinel.exists()) {
    782                 synchronized (mQueueLock) {
    783                     mPendingInits.add(transportName);
    784 
    785                     // TODO: pick a better starting time than now + 1 minute
    786                     long delay = 1000 * 60; // one minute, in milliseconds
    787                     mAlarmManager.set(AlarmManager.RTC_WAKEUP,
    788                             System.currentTimeMillis() + delay, mRunInitIntent);
    789                 }
    790             }
    791         } catch (RemoteException e) {
    792             // can't happen, the transport is local
    793         }
    794     }
    795 
    796     // ----- Track installation/removal of packages -----
    797     BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
    798         public void onReceive(Context context, Intent intent) {
    799             if (DEBUG) Slog.d(TAG, "Received broadcast " + intent);
    800 
    801             String action = intent.getAction();
    802             boolean replacing = false;
    803             boolean added = false;
    804             Bundle extras = intent.getExtras();
    805             String pkgList[] = null;
    806             if (Intent.ACTION_PACKAGE_ADDED.equals(action) ||
    807                     Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
    808                 Uri uri = intent.getData();
    809                 if (uri == null) {
    810                     return;
    811                 }
    812                 String pkgName = uri.getSchemeSpecificPart();
    813                 if (pkgName != null) {
    814                     pkgList = new String[] { pkgName };
    815                 }
    816                 added = Intent.ACTION_PACKAGE_ADDED.equals(action);
    817                 replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false);
    818             } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
    819                 added = true;
    820                 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
    821             } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
    822                 added = false;
    823                 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
    824             }
    825             if (pkgList == null || pkgList.length == 0) {
    826                 return;
    827             }
    828             if (added) {
    829                 synchronized (mBackupParticipants) {
    830                     for (String pkgName : pkgList) {
    831                         if (replacing) {
    832                             // The package was just upgraded
    833                             updatePackageParticipantsLocked(pkgName);
    834                         } else {
    835                             // The package was just added
    836                             addPackageParticipantsLocked(pkgName);
    837                         }
    838                     }
    839                 }
    840             } else {
    841                 if (replacing) {
    842                     // The package is being updated.  We'll receive a PACKAGE_ADDED shortly.
    843                 } else {
    844                     synchronized (mBackupParticipants) {
    845                         for (String pkgName : pkgList) {
    846                             removePackageParticipantsLocked(pkgName);
    847                         }
    848                     }
    849                 }
    850             }
    851         }
    852     };
    853 
    854     // ----- Track connection to GoogleBackupTransport service -----
    855     ServiceConnection mGoogleConnection = new ServiceConnection() {
    856         public void onServiceConnected(ComponentName name, IBinder service) {
    857             if (DEBUG) Slog.v(TAG, "Connected to Google transport");
    858             mGoogleTransport = IBackupTransport.Stub.asInterface(service);
    859             registerTransport(name.flattenToShortString(), mGoogleTransport);
    860         }
    861 
    862         public void onServiceDisconnected(ComponentName name) {
    863             if (DEBUG) Slog.v(TAG, "Disconnected from Google transport");
    864             mGoogleTransport = null;
    865             registerTransport(name.flattenToShortString(), null);
    866         }
    867     };
    868 
    869     // Add the backup agents in the given package to our set of known backup participants.
    870     // If 'packageName' is null, adds all backup agents in the whole system.
    871     void addPackageParticipantsLocked(String packageName) {
    872         // Look for apps that define the android:backupAgent attribute
    873         if (DEBUG) Slog.v(TAG, "addPackageParticipantsLocked: " + packageName);
    874         List<PackageInfo> targetApps = allAgentPackages();
    875         addPackageParticipantsLockedInner(packageName, targetApps);
    876     }
    877 
    878     private void addPackageParticipantsLockedInner(String packageName,
    879             List<PackageInfo> targetPkgs) {
    880         if (DEBUG) {
    881             Slog.v(TAG, "Adding " + targetPkgs.size() + " backup participants:");
    882             for (PackageInfo p : targetPkgs) {
    883                 Slog.v(TAG, "    " + p + " agent=" + p.applicationInfo.backupAgentName
    884                         + " uid=" + p.applicationInfo.uid
    885                         + " killAfterRestore="
    886                         + (((p.applicationInfo.flags & ApplicationInfo.FLAG_KILL_AFTER_RESTORE) != 0) ? "true" : "false")
    887                         );
    888             }
    889         }
    890 
    891         for (PackageInfo pkg : targetPkgs) {
    892             if (packageName == null || pkg.packageName.equals(packageName)) {
    893                 int uid = pkg.applicationInfo.uid;
    894                 HashSet<ApplicationInfo> set = mBackupParticipants.get(uid);
    895                 if (set == null) {
    896                     set = new HashSet<ApplicationInfo>();
    897                     mBackupParticipants.put(uid, set);
    898                 }
    899                 set.add(pkg.applicationInfo);
    900 
    901                 // If we've never seen this app before, schedule a backup for it
    902                 if (!mEverStoredApps.contains(pkg.packageName)) {
    903                     if (DEBUG) Slog.i(TAG, "New app " + pkg.packageName
    904                             + " never backed up; scheduling");
    905                     dataChangedImpl(pkg.packageName);
    906                 }
    907             }
    908         }
    909     }
    910 
    911     // Remove the given package's entry from our known active set.  If
    912     // 'packageName' is null, *all* participating apps will be removed.
    913     void removePackageParticipantsLocked(String packageName) {
    914         if (DEBUG) Slog.v(TAG, "removePackageParticipantsLocked: " + packageName);
    915         List<PackageInfo> allApps = null;
    916         if (packageName != null) {
    917             allApps = new ArrayList<PackageInfo>();
    918             try {
    919                 int flags = PackageManager.GET_SIGNATURES;
    920                 allApps.add(mPackageManager.getPackageInfo(packageName, flags));
    921             } catch (Exception e) {
    922                 // just skip it (???)
    923             }
    924         } else {
    925             // all apps with agents
    926             allApps = allAgentPackages();
    927         }
    928         removePackageParticipantsLockedInner(packageName, allApps);
    929     }
    930 
    931     private void removePackageParticipantsLockedInner(String packageName,
    932             List<PackageInfo> agents) {
    933         if (DEBUG) {
    934             Slog.v(TAG, "removePackageParticipantsLockedInner (" + packageName
    935                     + ") removing " + agents.size() + " entries");
    936             for (PackageInfo p : agents) {
    937                 Slog.v(TAG, "    - " + p);
    938             }
    939         }
    940         for (PackageInfo pkg : agents) {
    941             if (packageName == null || pkg.packageName.equals(packageName)) {
    942                 int uid = pkg.applicationInfo.uid;
    943                 HashSet<ApplicationInfo> set = mBackupParticipants.get(uid);
    944                 if (set != null) {
    945                     // Find the existing entry with the same package name, and remove it.
    946                     // We can't just remove(app) because the instances are different.
    947                     for (ApplicationInfo entry: set) {
    948                         if (entry.packageName.equals(pkg.packageName)) {
    949                             set.remove(entry);
    950                             removeEverBackedUp(pkg.packageName);
    951                             break;
    952                         }
    953                     }
    954                     if (set.size() == 0) {
    955                         mBackupParticipants.delete(uid);
    956                     }
    957                 }
    958             }
    959         }
    960     }
    961 
    962     // Returns the set of all applications that define an android:backupAgent attribute
    963     List<PackageInfo> allAgentPackages() {
    964         // !!! TODO: cache this and regenerate only when necessary
    965         int flags = PackageManager.GET_SIGNATURES;
    966         List<PackageInfo> packages = mPackageManager.getInstalledPackages(flags);
    967         int N = packages.size();
    968         for (int a = N-1; a >= 0; a--) {
    969             PackageInfo pkg = packages.get(a);
    970             try {
    971                 ApplicationInfo app = pkg.applicationInfo;
    972                 if (((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0)
    973                         || app.backupAgentName == null) {
    974                     packages.remove(a);
    975                 }
    976                 else {
    977                     // we will need the shared library path, so look that up and store it here
    978                     app = mPackageManager.getApplicationInfo(pkg.packageName,
    979                             PackageManager.GET_SHARED_LIBRARY_FILES);
    980                     pkg.applicationInfo.sharedLibraryFiles = app.sharedLibraryFiles;
    981                 }
    982             } catch (NameNotFoundException e) {
    983                 packages.remove(a);
    984             }
    985         }
    986         return packages;
    987     }
    988 
    989     // Reset the given package's known backup participants.  Unlike add/remove, the update
    990     // action cannot be passed a null package name.
    991     void updatePackageParticipantsLocked(String packageName) {
    992         if (packageName == null) {
    993             Slog.e(TAG, "updatePackageParticipants called with null package name");
    994             return;
    995         }
    996         if (DEBUG) Slog.v(TAG, "updatePackageParticipantsLocked: " + packageName);
    997 
    998         // brute force but small code size
    999         List<PackageInfo> allApps = allAgentPackages();
   1000         removePackageParticipantsLockedInner(packageName, allApps);
   1001         addPackageParticipantsLockedInner(packageName, allApps);
   1002     }
   1003 
   1004     // Called from the backup task: record that the given app has been successfully
   1005     // backed up at least once
   1006     void logBackupComplete(String packageName) {
   1007         if (packageName.equals(PACKAGE_MANAGER_SENTINEL)) return;
   1008 
   1009         synchronized (mEverStoredApps) {
   1010             if (!mEverStoredApps.add(packageName)) return;
   1011 
   1012             RandomAccessFile out = null;
   1013             try {
   1014                 out = new RandomAccessFile(mEverStored, "rws");
   1015                 out.seek(out.length());
   1016                 out.writeUTF(packageName);
   1017             } catch (IOException e) {
   1018                 Slog.e(TAG, "Can't log backup of " + packageName + " to " + mEverStored);
   1019             } finally {
   1020                 try { if (out != null) out.close(); } catch (IOException e) {}
   1021             }
   1022         }
   1023     }
   1024 
   1025     // Remove our awareness of having ever backed up the given package
   1026     void removeEverBackedUp(String packageName) {
   1027         if (DEBUG) Slog.v(TAG, "Removing backed-up knowledge of " + packageName + ", new set:");
   1028 
   1029         synchronized (mEverStoredApps) {
   1030             // Rewrite the file and rename to overwrite.  If we reboot in the middle,
   1031             // we'll recognize on initialization time that the package no longer
   1032             // exists and fix it up then.
   1033             File tempKnownFile = new File(mBaseStateDir, "processed.new");
   1034             RandomAccessFile known = null;
   1035             try {
   1036                 known = new RandomAccessFile(tempKnownFile, "rws");
   1037                 mEverStoredApps.remove(packageName);
   1038                 for (String s : mEverStoredApps) {
   1039                     known.writeUTF(s);
   1040                     if (DEBUG) Slog.v(TAG, "    " + s);
   1041                 }
   1042                 known.close();
   1043                 known = null;
   1044                 if (!tempKnownFile.renameTo(mEverStored)) {
   1045                     throw new IOException("Can't rename " + tempKnownFile + " to " + mEverStored);
   1046                 }
   1047             } catch (IOException e) {
   1048                 // Bad: we couldn't create the new copy.  For safety's sake we
   1049                 // abandon the whole process and remove all what's-backed-up
   1050                 // state entirely, meaning we'll force a backup pass for every
   1051                 // participant on the next boot or [re]install.
   1052                 Slog.w(TAG, "Error rewriting " + mEverStored, e);
   1053                 mEverStoredApps.clear();
   1054                 tempKnownFile.delete();
   1055                 mEverStored.delete();
   1056             } finally {
   1057                 try { if (known != null) known.close(); } catch (IOException e) {}
   1058             }
   1059         }
   1060     }
   1061 
   1062     // Persistently record the current and ancestral backup tokens as well
   1063     // as the set of packages with data [supposedly] available in the
   1064     // ancestral dataset.
   1065     void writeRestoreTokens() {
   1066         try {
   1067             RandomAccessFile af = new RandomAccessFile(mTokenFile, "rwd");
   1068 
   1069             // First, the version number of this record, for futureproofing
   1070             af.writeInt(CURRENT_ANCESTRAL_RECORD_VERSION);
   1071 
   1072             // Write the ancestral and current tokens
   1073             af.writeLong(mAncestralToken);
   1074             af.writeLong(mCurrentToken);
   1075 
   1076             // Now write the set of ancestral packages
   1077             if (mAncestralPackages == null) {
   1078                 af.writeInt(-1);
   1079             } else {
   1080                 af.writeInt(mAncestralPackages.size());
   1081                 if (DEBUG) Slog.v(TAG, "Ancestral packages:  " + mAncestralPackages.size());
   1082                 for (String pkgName : mAncestralPackages) {
   1083                     af.writeUTF(pkgName);
   1084                     if (DEBUG) Slog.v(TAG, "   " + pkgName);
   1085                 }
   1086             }
   1087             af.close();
   1088         } catch (IOException e) {
   1089             Slog.w(TAG, "Unable to write token file:", e);
   1090         }
   1091     }
   1092 
   1093     // Return the given transport
   1094     private IBackupTransport getTransport(String transportName) {
   1095         synchronized (mTransports) {
   1096             IBackupTransport transport = mTransports.get(transportName);
   1097             if (transport == null) {
   1098                 Slog.w(TAG, "Requested unavailable transport: " + transportName);
   1099             }
   1100             return transport;
   1101         }
   1102     }
   1103 
   1104     // fire off a backup agent, blocking until it attaches or times out
   1105     IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode) {
   1106         IBackupAgent agent = null;
   1107         synchronized(mAgentConnectLock) {
   1108             mConnecting = true;
   1109             mConnectedAgent = null;
   1110             try {
   1111                 if (mActivityManager.bindBackupAgent(app, mode)) {
   1112                     Slog.d(TAG, "awaiting agent for " + app);
   1113 
   1114                     // success; wait for the agent to arrive
   1115                     // only wait 10 seconds for the clear data to happen
   1116                     long timeoutMark = System.currentTimeMillis() + TIMEOUT_INTERVAL;
   1117                     while (mConnecting && mConnectedAgent == null
   1118                             && (System.currentTimeMillis() < timeoutMark)) {
   1119                         try {
   1120                             mAgentConnectLock.wait(5000);
   1121                         } catch (InterruptedException e) {
   1122                             // just bail
   1123                             return null;
   1124                         }
   1125                     }
   1126 
   1127                     // if we timed out with no connect, abort and move on
   1128                     if (mConnecting == true) {
   1129                         Slog.w(TAG, "Timeout waiting for agent " + app);
   1130                         return null;
   1131                     }
   1132                     agent = mConnectedAgent;
   1133                 }
   1134             } catch (RemoteException e) {
   1135                 // can't happen
   1136             }
   1137         }
   1138         return agent;
   1139     }
   1140 
   1141     // clear an application's data, blocking until the operation completes or times out
   1142     void clearApplicationDataSynchronous(String packageName) {
   1143         // Don't wipe packages marked allowClearUserData=false
   1144         try {
   1145             PackageInfo info = mPackageManager.getPackageInfo(packageName, 0);
   1146             if ((info.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA) == 0) {
   1147                 if (DEBUG) Slog.i(TAG, "allowClearUserData=false so not wiping "
   1148                         + packageName);
   1149                 return;
   1150             }
   1151         } catch (NameNotFoundException e) {
   1152             Slog.w(TAG, "Tried to clear data for " + packageName + " but not found");
   1153             return;
   1154         }
   1155 
   1156         ClearDataObserver observer = new ClearDataObserver();
   1157 
   1158         synchronized(mClearDataLock) {
   1159             mClearingData = true;
   1160             try {
   1161                 mActivityManager.clearApplicationUserData(packageName, observer);
   1162             } catch (RemoteException e) {
   1163                 // can't happen because the activity manager is in this process
   1164             }
   1165 
   1166             // only wait 10 seconds for the clear data to happen
   1167             long timeoutMark = System.currentTimeMillis() + TIMEOUT_INTERVAL;
   1168             while (mClearingData && (System.currentTimeMillis() < timeoutMark)) {
   1169                 try {
   1170                     mClearDataLock.wait(5000);
   1171                 } catch (InterruptedException e) {
   1172                     // won't happen, but still.
   1173                     mClearingData = false;
   1174                 }
   1175             }
   1176         }
   1177     }
   1178 
   1179     class ClearDataObserver extends IPackageDataObserver.Stub {
   1180         public void onRemoveCompleted(String packageName, boolean succeeded) {
   1181             synchronized(mClearDataLock) {
   1182                 mClearingData = false;
   1183                 mClearDataLock.notifyAll();
   1184             }
   1185         }
   1186     }
   1187 
   1188     // Get the restore-set token for the best-available restore set for this package:
   1189     // the active set if possible, else the ancestral one.  Returns zero if none available.
   1190     long getAvailableRestoreToken(String packageName) {
   1191         long token = mAncestralToken;
   1192         synchronized (mQueueLock) {
   1193             if (mEverStoredApps.contains(packageName)) {
   1194                 token = mCurrentToken;
   1195             }
   1196         }
   1197         return token;
   1198     }
   1199 
   1200     // -----
   1201     // Utility methods used by the asynchronous-with-timeout backup/restore operations
   1202     boolean waitUntilOperationComplete(int token) {
   1203         int finalState = OP_PENDING;
   1204         synchronized (mCurrentOpLock) {
   1205             try {
   1206                 while ((finalState = mCurrentOperations.get(token, OP_TIMEOUT)) == OP_PENDING) {
   1207                     try {
   1208                         mCurrentOpLock.wait();
   1209                     } catch (InterruptedException e) {}
   1210                 }
   1211             } catch (IndexOutOfBoundsException e) {
   1212                 // the operation has been mysteriously cleared from our
   1213                 // bookkeeping -- consider this a success and ignore it.
   1214             }
   1215         }
   1216         mBackupHandler.removeMessages(MSG_TIMEOUT);
   1217         if (DEBUG) Slog.v(TAG, "operation " + Integer.toHexString(token)
   1218                 + " complete: finalState=" + finalState);
   1219         return finalState == OP_ACKNOWLEDGED;
   1220     }
   1221 
   1222     void prepareOperationTimeout(int token, long interval) {
   1223         if (DEBUG) Slog.v(TAG, "starting timeout: token=" + Integer.toHexString(token)
   1224                 + " interval=" + interval);
   1225         mCurrentOperations.put(token, OP_PENDING);
   1226         Message msg = mBackupHandler.obtainMessage(MSG_TIMEOUT, token, 0);
   1227         mBackupHandler.sendMessageDelayed(msg, interval);
   1228     }
   1229 
   1230     // ----- Back up a set of applications via a worker thread -----
   1231 
   1232     class PerformBackupTask implements Runnable {
   1233         private static final String TAG = "PerformBackupThread";
   1234         IBackupTransport mTransport;
   1235         ArrayList<BackupRequest> mQueue;
   1236         File mStateDir;
   1237         File mJournal;
   1238 
   1239         public PerformBackupTask(IBackupTransport transport, ArrayList<BackupRequest> queue,
   1240                 File journal) {
   1241             mTransport = transport;
   1242             mQueue = queue;
   1243             mJournal = journal;
   1244 
   1245             try {
   1246                 mStateDir = new File(mBaseStateDir, transport.transportDirName());
   1247             } catch (RemoteException e) {
   1248                 // can't happen; the transport is local
   1249             }
   1250         }
   1251 
   1252         public void run() {
   1253             int status = BackupConstants.TRANSPORT_OK;
   1254             long startRealtime = SystemClock.elapsedRealtime();
   1255             if (DEBUG) Slog.v(TAG, "Beginning backup of " + mQueue.size() + " targets");
   1256 
   1257             // Backups run at background priority
   1258             Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
   1259 
   1260             try {
   1261                 EventLog.writeEvent(EventLogTags.BACKUP_START, mTransport.transportDirName());
   1262 
   1263                 // If we haven't stored package manager metadata yet, we must init the transport.
   1264                 File pmState = new File(mStateDir, PACKAGE_MANAGER_SENTINEL);
   1265                 if (status == BackupConstants.TRANSPORT_OK && pmState.length() <= 0) {
   1266                     Slog.i(TAG, "Initializing (wiping) backup state and transport storage");
   1267                     resetBackupState(mStateDir);  // Just to make sure.
   1268                     status = mTransport.initializeDevice();
   1269                     if (status == BackupConstants.TRANSPORT_OK) {
   1270                         EventLog.writeEvent(EventLogTags.BACKUP_INITIALIZE);
   1271                     } else {
   1272                         EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, "(initialize)");
   1273                         Slog.e(TAG, "Transport error in initializeDevice()");
   1274                     }
   1275                 }
   1276 
   1277                 // The package manager doesn't have a proper <application> etc, but since
   1278                 // it's running here in the system process we can just set up its agent
   1279                 // directly and use a synthetic BackupRequest.  We always run this pass
   1280                 // because it's cheap and this way we guarantee that we don't get out of
   1281                 // step even if we're selecting among various transports at run time.
   1282                 if (status == BackupConstants.TRANSPORT_OK) {
   1283                     PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
   1284                             mPackageManager, allAgentPackages());
   1285                     BackupRequest pmRequest = new BackupRequest(new ApplicationInfo(), false);
   1286                     pmRequest.appInfo.packageName = PACKAGE_MANAGER_SENTINEL;
   1287                     status = processOneBackup(pmRequest,
   1288                             IBackupAgent.Stub.asInterface(pmAgent.onBind()), mTransport);
   1289                 }
   1290 
   1291                 if (status == BackupConstants.TRANSPORT_OK) {
   1292                     // Now run all the backups in our queue
   1293                     status = doQueuedBackups(mTransport);
   1294                 }
   1295 
   1296                 if (status == BackupConstants.TRANSPORT_OK) {
   1297                     // Tell the transport to finish everything it has buffered
   1298                     status = mTransport.finishBackup();
   1299                     if (status == BackupConstants.TRANSPORT_OK) {
   1300                         int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
   1301                         EventLog.writeEvent(EventLogTags.BACKUP_SUCCESS, mQueue.size(), millis);
   1302                     } else {
   1303                         EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, "(finish)");
   1304                         Slog.e(TAG, "Transport error in finishBackup()");
   1305                     }
   1306                 }
   1307 
   1308                 if (status == BackupConstants.TRANSPORT_NOT_INITIALIZED) {
   1309                     // The backend reports that our dataset has been wiped.  We need to
   1310                     // reset all of our bookkeeping and instead run a new backup pass for
   1311                     // everything.
   1312                     EventLog.writeEvent(EventLogTags.BACKUP_RESET, mTransport.transportDirName());
   1313                     resetBackupState(mStateDir);
   1314                 }
   1315             } catch (Exception e) {
   1316                 Slog.e(TAG, "Error in backup thread", e);
   1317                 status = BackupConstants.TRANSPORT_ERROR;
   1318             } finally {
   1319                 // If everything actually went through and this is the first time we've
   1320                 // done a backup, we can now record what the current backup dataset token
   1321                 // is.
   1322                 if ((mCurrentToken == 0) && (status == BackupConstants.TRANSPORT_OK)) {
   1323                     try {
   1324                         mCurrentToken = mTransport.getCurrentRestoreSet();
   1325                     } catch (RemoteException e) { /* cannot happen */ }
   1326                     writeRestoreTokens();
   1327                 }
   1328 
   1329                 // If things went wrong, we need to re-stage the apps we had expected
   1330                 // to be backing up in this pass.  This journals the package names in
   1331                 // the current active pending-backup file, not in the we are holding
   1332                 // here in mJournal.
   1333                 if (status != BackupConstants.TRANSPORT_OK) {
   1334                     Slog.w(TAG, "Backup pass unsuccessful, restaging");
   1335                     for (BackupRequest req : mQueue) {
   1336                         dataChangedImpl(req.appInfo.packageName);
   1337                     }
   1338 
   1339                     // We also want to reset the backup schedule based on whatever
   1340                     // the transport suggests by way of retry/backoff time.
   1341                     try {
   1342                         startBackupAlarmsLocked(mTransport.requestBackupTime());
   1343                     } catch (RemoteException e) { /* cannot happen */ }
   1344                 }
   1345 
   1346                 // Either backup was successful, in which case we of course do not need
   1347                 // this pass's journal any more; or it failed, in which case we just
   1348                 // re-enqueued all of these packages in the current active journal.
   1349                 // Either way, we no longer need this pass's journal.
   1350                 if (mJournal != null && !mJournal.delete()) {
   1351                     Slog.e(TAG, "Unable to remove backup journal file " + mJournal);
   1352                 }
   1353 
   1354                 // Only once we're entirely finished do we release the wakelock
   1355                 if (status == BackupConstants.TRANSPORT_NOT_INITIALIZED) {
   1356                     backupNow();
   1357                 }
   1358 
   1359                 mWakelock.release();
   1360             }
   1361         }
   1362 
   1363         private int doQueuedBackups(IBackupTransport transport) {
   1364             for (BackupRequest request : mQueue) {
   1365                 Slog.d(TAG, "starting agent for backup of " + request);
   1366 
   1367                 IBackupAgent agent = null;
   1368                 int mode = (request.fullBackup)
   1369                         ? IApplicationThread.BACKUP_MODE_FULL
   1370                         : IApplicationThread.BACKUP_MODE_INCREMENTAL;
   1371                 try {
   1372                     mWakelock.setWorkSource(new WorkSource(request.appInfo.uid));
   1373                     agent = bindToAgentSynchronous(request.appInfo, mode);
   1374                     if (agent != null) {
   1375                         int result = processOneBackup(request, agent, transport);
   1376                         if (result != BackupConstants.TRANSPORT_OK) return result;
   1377                     }
   1378                 } catch (SecurityException ex) {
   1379                     // Try for the next one.
   1380                     Slog.d(TAG, "error in bind/backup", ex);
   1381                 } finally {
   1382                     try {  // unbind even on timeout, just in case
   1383                         mActivityManager.unbindBackupAgent(request.appInfo);
   1384                     } catch (RemoteException e) {}
   1385                 }
   1386             }
   1387 
   1388             mWakelock.setWorkSource(null);
   1389 
   1390             return BackupConstants.TRANSPORT_OK;
   1391         }
   1392 
   1393         private int processOneBackup(BackupRequest request, IBackupAgent agent,
   1394                 IBackupTransport transport) {
   1395             final String packageName = request.appInfo.packageName;
   1396             if (DEBUG) Slog.d(TAG, "processOneBackup doBackup() on " + packageName);
   1397 
   1398             File savedStateName = new File(mStateDir, packageName);
   1399             File backupDataName = new File(mDataDir, packageName + ".data");
   1400             File newStateName = new File(mStateDir, packageName + ".new");
   1401 
   1402             ParcelFileDescriptor savedState = null;
   1403             ParcelFileDescriptor backupData = null;
   1404             ParcelFileDescriptor newState = null;
   1405 
   1406             PackageInfo packInfo;
   1407             int token = mTokenGenerator.nextInt();
   1408             try {
   1409                 // Look up the package info & signatures.  This is first so that if it
   1410                 // throws an exception, there's no file setup yet that would need to
   1411                 // be unraveled.
   1412                 if (packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
   1413                     // The metadata 'package' is synthetic
   1414                     packInfo = new PackageInfo();
   1415                     packInfo.packageName = packageName;
   1416                 } else {
   1417                     packInfo = mPackageManager.getPackageInfo(packageName,
   1418                         PackageManager.GET_SIGNATURES);
   1419                 }
   1420 
   1421                 // In a full backup, we pass a null ParcelFileDescriptor as
   1422                 // the saved-state "file"
   1423                 if (!request.fullBackup) {
   1424                     savedState = ParcelFileDescriptor.open(savedStateName,
   1425                             ParcelFileDescriptor.MODE_READ_ONLY |
   1426                             ParcelFileDescriptor.MODE_CREATE);  // Make an empty file if necessary
   1427                 }
   1428 
   1429                 backupData = ParcelFileDescriptor.open(backupDataName,
   1430                         ParcelFileDescriptor.MODE_READ_WRITE |
   1431                         ParcelFileDescriptor.MODE_CREATE |
   1432                         ParcelFileDescriptor.MODE_TRUNCATE);
   1433 
   1434                 newState = ParcelFileDescriptor.open(newStateName,
   1435                         ParcelFileDescriptor.MODE_READ_WRITE |
   1436                         ParcelFileDescriptor.MODE_CREATE |
   1437                         ParcelFileDescriptor.MODE_TRUNCATE);
   1438 
   1439                 // Initiate the target's backup pass
   1440                 prepareOperationTimeout(token, TIMEOUT_BACKUP_INTERVAL);
   1441                 agent.doBackup(savedState, backupData, newState, token, mBackupManagerBinder);
   1442                 boolean success = waitUntilOperationComplete(token);
   1443 
   1444                 if (!success) {
   1445                     // timeout -- bail out into the failed-transaction logic
   1446                     throw new RuntimeException("Backup timeout");
   1447                 }
   1448 
   1449                 logBackupComplete(packageName);
   1450                 if (DEBUG) Slog.v(TAG, "doBackup() success");
   1451             } catch (Exception e) {
   1452                 Slog.e(TAG, "Error backing up " + packageName, e);
   1453                 EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName, e.toString());
   1454                 backupDataName.delete();
   1455                 newStateName.delete();
   1456                 return BackupConstants.TRANSPORT_ERROR;
   1457             } finally {
   1458                 try { if (savedState != null) savedState.close(); } catch (IOException e) {}
   1459                 try { if (backupData != null) backupData.close(); } catch (IOException e) {}
   1460                 try { if (newState != null) newState.close(); } catch (IOException e) {}
   1461                 savedState = backupData = newState = null;
   1462                 synchronized (mCurrentOpLock) {
   1463                     mCurrentOperations.clear();
   1464                 }
   1465             }
   1466 
   1467             // Now propagate the newly-backed-up data to the transport
   1468             int result = BackupConstants.TRANSPORT_OK;
   1469             try {
   1470                 int size = (int) backupDataName.length();
   1471                 if (size > 0) {
   1472                     if (result == BackupConstants.TRANSPORT_OK) {
   1473                         backupData = ParcelFileDescriptor.open(backupDataName,
   1474                                 ParcelFileDescriptor.MODE_READ_ONLY);
   1475                         result = transport.performBackup(packInfo, backupData);
   1476                     }
   1477 
   1478                     // TODO - We call finishBackup() for each application backed up, because
   1479                     // we need to know now whether it succeeded or failed.  Instead, we should
   1480                     // hold off on finishBackup() until the end, which implies holding off on
   1481                     // renaming *all* the output state files (see below) until that happens.
   1482 
   1483                     if (result == BackupConstants.TRANSPORT_OK) {
   1484                         result = transport.finishBackup();
   1485                     }
   1486                 } else {
   1487                     if (DEBUG) Slog.i(TAG, "no backup data written; not calling transport");
   1488                 }
   1489 
   1490                 // After successful transport, delete the now-stale data
   1491                 // and juggle the files so that next time we supply the agent
   1492                 // with the new state file it just created.
   1493                 if (result == BackupConstants.TRANSPORT_OK) {
   1494                     backupDataName.delete();
   1495                     newStateName.renameTo(savedStateName);
   1496                     EventLog.writeEvent(EventLogTags.BACKUP_PACKAGE, packageName, size);
   1497                 } else {
   1498                     EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, packageName);
   1499                 }
   1500             } catch (Exception e) {
   1501                 Slog.e(TAG, "Transport error backing up " + packageName, e);
   1502                 EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, packageName);
   1503                 result = BackupConstants.TRANSPORT_ERROR;
   1504             } finally {
   1505                 try { if (backupData != null) backupData.close(); } catch (IOException e) {}
   1506             }
   1507 
   1508             return result;
   1509         }
   1510     }
   1511 
   1512 
   1513     // ----- Restore handling -----
   1514 
   1515     private boolean signaturesMatch(Signature[] storedSigs, PackageInfo target) {
   1516         // If the target resides on the system partition, we allow it to restore
   1517         // data from the like-named package in a restore set even if the signatures
   1518         // do not match.  (Unlike general applications, those flashed to the system
   1519         // partition will be signed with the device's platform certificate, so on
   1520         // different phones the same system app will have different signatures.)
   1521         if ((target.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
   1522             if (DEBUG) Slog.v(TAG, "System app " + target.packageName + " - skipping sig check");
   1523             return true;
   1524         }
   1525 
   1526         // Allow unsigned apps, but not signed on one device and unsigned on the other
   1527         // !!! TODO: is this the right policy?
   1528         Signature[] deviceSigs = target.signatures;
   1529         if (DEBUG) Slog.v(TAG, "signaturesMatch(): stored=" + storedSigs
   1530                 + " device=" + deviceSigs);
   1531         if ((storedSigs == null || storedSigs.length == 0)
   1532                 && (deviceSigs == null || deviceSigs.length == 0)) {
   1533             return true;
   1534         }
   1535         if (storedSigs == null || deviceSigs == null) {
   1536             return false;
   1537         }
   1538 
   1539         // !!! TODO: this demands that every stored signature match one
   1540         // that is present on device, and does not demand the converse.
   1541         // Is this this right policy?
   1542         int nStored = storedSigs.length;
   1543         int nDevice = deviceSigs.length;
   1544 
   1545         for (int i=0; i < nStored; i++) {
   1546             boolean match = false;
   1547             for (int j=0; j < nDevice; j++) {
   1548                 if (storedSigs[i].equals(deviceSigs[j])) {
   1549                     match = true;
   1550                     break;
   1551                 }
   1552             }
   1553             if (!match) {
   1554                 return false;
   1555             }
   1556         }
   1557         return true;
   1558     }
   1559 
   1560     class PerformRestoreTask implements Runnable {
   1561         private IBackupTransport mTransport;
   1562         private IRestoreObserver mObserver;
   1563         private long mToken;
   1564         private PackageInfo mTargetPackage;
   1565         private File mStateDir;
   1566         private int mPmToken;
   1567         private boolean mNeedFullBackup;
   1568 
   1569         class RestoreRequest {
   1570             public PackageInfo app;
   1571             public int storedAppVersion;
   1572 
   1573             RestoreRequest(PackageInfo _app, int _version) {
   1574                 app = _app;
   1575                 storedAppVersion = _version;
   1576             }
   1577         }
   1578 
   1579         PerformRestoreTask(IBackupTransport transport, IRestoreObserver observer,
   1580                 long restoreSetToken, PackageInfo targetPackage, int pmToken,
   1581                 boolean needFullBackup) {
   1582             mTransport = transport;
   1583             mObserver = observer;
   1584             mToken = restoreSetToken;
   1585             mTargetPackage = targetPackage;
   1586             mPmToken = pmToken;
   1587             mNeedFullBackup = needFullBackup;
   1588 
   1589             try {
   1590                 mStateDir = new File(mBaseStateDir, transport.transportDirName());
   1591             } catch (RemoteException e) {
   1592                 // can't happen; the transport is local
   1593             }
   1594         }
   1595 
   1596         public void run() {
   1597             long startRealtime = SystemClock.elapsedRealtime();
   1598             if (DEBUG) Slog.v(TAG, "Beginning restore process mTransport=" + mTransport
   1599                     + " mObserver=" + mObserver + " mToken=" + Long.toHexString(mToken)
   1600                     + " mTargetPackage=" + mTargetPackage + " mPmToken=" + mPmToken);
   1601 
   1602             PackageManagerBackupAgent pmAgent = null;
   1603             int error = -1; // assume error
   1604 
   1605             // build the set of apps to restore
   1606             try {
   1607                 // TODO: Log this before getAvailableRestoreSets, somehow
   1608                 EventLog.writeEvent(EventLogTags.RESTORE_START, mTransport.transportDirName(), mToken);
   1609 
   1610                 // Get the list of all packages which have backup enabled.
   1611                 // (Include the Package Manager metadata pseudo-package first.)
   1612                 ArrayList<PackageInfo> restorePackages = new ArrayList<PackageInfo>();
   1613                 PackageInfo omPackage = new PackageInfo();
   1614                 omPackage.packageName = PACKAGE_MANAGER_SENTINEL;
   1615                 restorePackages.add(omPackage);
   1616 
   1617                 List<PackageInfo> agentPackages = allAgentPackages();
   1618                 if (mTargetPackage == null) {
   1619                     restorePackages.addAll(agentPackages);
   1620                 } else {
   1621                     // Just one package to attempt restore of
   1622                     restorePackages.add(mTargetPackage);
   1623                 }
   1624 
   1625                 // let the observer know that we're running
   1626                 if (mObserver != null) {
   1627                     try {
   1628                         // !!! TODO: get an actual count from the transport after
   1629                         // its startRestore() runs?
   1630                         mObserver.restoreStarting(restorePackages.size());
   1631                     } catch (RemoteException e) {
   1632                         Slog.d(TAG, "Restore observer died at restoreStarting");
   1633                         mObserver = null;
   1634                     }
   1635                 }
   1636 
   1637                 if (mTransport.startRestore(mToken, restorePackages.toArray(new PackageInfo[0])) !=
   1638                         BackupConstants.TRANSPORT_OK) {
   1639                     Slog.e(TAG, "Error starting restore operation");
   1640                     EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
   1641                     return;
   1642                 }
   1643 
   1644                 String packageName = mTransport.nextRestorePackage();
   1645                 if (packageName == null) {
   1646                     Slog.e(TAG, "Error getting first restore package");
   1647                     EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
   1648                     return;
   1649                 } else if (packageName.equals("")) {
   1650                     Slog.i(TAG, "No restore data available");
   1651                     int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
   1652                     EventLog.writeEvent(EventLogTags.RESTORE_SUCCESS, 0, millis);
   1653                     return;
   1654                 } else if (!packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
   1655                     Slog.e(TAG, "Expected restore data for \"" + PACKAGE_MANAGER_SENTINEL
   1656                           + "\", found only \"" + packageName + "\"");
   1657                     EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, PACKAGE_MANAGER_SENTINEL,
   1658                             "Package manager data missing");
   1659                     return;
   1660                 }
   1661 
   1662                 // Pull the Package Manager metadata from the restore set first
   1663                 pmAgent = new PackageManagerBackupAgent(
   1664                         mPackageManager, agentPackages);
   1665                 processOneRestore(omPackage, 0, IBackupAgent.Stub.asInterface(pmAgent.onBind()),
   1666                         mNeedFullBackup);
   1667 
   1668                 // Verify that the backup set includes metadata.  If not, we can't do
   1669                 // signature/version verification etc, so we simply do not proceed with
   1670                 // the restore operation.
   1671                 if (!pmAgent.hasMetadata()) {
   1672                     Slog.e(TAG, "No restore metadata available, so not restoring settings");
   1673                     EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, PACKAGE_MANAGER_SENTINEL,
   1674                             "Package manager restore metadata missing");
   1675                     return;
   1676                 }
   1677 
   1678                 int count = 0;
   1679                 for (;;) {
   1680                     packageName = mTransport.nextRestorePackage();
   1681 
   1682                     if (packageName == null) {
   1683                         Slog.e(TAG, "Error getting next restore package");
   1684                         EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
   1685                         return;
   1686                     } else if (packageName.equals("")) {
   1687                         if (DEBUG) Slog.v(TAG, "No next package, finishing restore");
   1688                         break;
   1689                     }
   1690 
   1691                     if (mObserver != null) {
   1692                         try {
   1693                             mObserver.onUpdate(count, packageName);
   1694                         } catch (RemoteException e) {
   1695                             Slog.d(TAG, "Restore observer died in onUpdate");
   1696                             mObserver = null;
   1697                         }
   1698                     }
   1699 
   1700                     Metadata metaInfo = pmAgent.getRestoredMetadata(packageName);
   1701                     if (metaInfo == null) {
   1702                         Slog.e(TAG, "Missing metadata for " + packageName);
   1703                         EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
   1704                                 "Package metadata missing");
   1705                         continue;
   1706                     }
   1707 
   1708                     PackageInfo packageInfo;
   1709                     try {
   1710                         int flags = PackageManager.GET_SIGNATURES;
   1711                         packageInfo = mPackageManager.getPackageInfo(packageName, flags);
   1712                     } catch (NameNotFoundException e) {
   1713                         Slog.e(TAG, "Invalid package restoring data", e);
   1714                         EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
   1715                                 "Package missing on device");
   1716                         continue;
   1717                     }
   1718 
   1719                     if (metaInfo.versionCode > packageInfo.versionCode) {
   1720                         // Data is from a "newer" version of the app than we have currently
   1721                         // installed.  If the app has not declared that it is prepared to
   1722                         // handle this case, we do not attempt the restore.
   1723                         if ((packageInfo.applicationInfo.flags
   1724                                 & ApplicationInfo.FLAG_RESTORE_ANY_VERSION) == 0) {
   1725                             String message = "Version " + metaInfo.versionCode
   1726                                     + " > installed version " + packageInfo.versionCode;
   1727                             Slog.w(TAG, "Package " + packageName + ": " + message);
   1728                             EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
   1729                                     packageName, message);
   1730                             continue;
   1731                         } else {
   1732                             if (DEBUG) Slog.v(TAG, "Version " + metaInfo.versionCode
   1733                                     + " > installed " + packageInfo.versionCode
   1734                                     + " but restoreAnyVersion");
   1735                         }
   1736                     }
   1737 
   1738                     if (!signaturesMatch(metaInfo.signatures, packageInfo)) {
   1739                         Slog.w(TAG, "Signature mismatch restoring " + packageName);
   1740                         EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
   1741                                 "Signature mismatch");
   1742                         continue;
   1743                     }
   1744 
   1745                     if (DEBUG) Slog.v(TAG, "Package " + packageName
   1746                             + " restore version [" + metaInfo.versionCode
   1747                             + "] is compatible with installed version ["
   1748                             + packageInfo.versionCode + "]");
   1749 
   1750                     // Then set up and bind the agent
   1751                     IBackupAgent agent = bindToAgentSynchronous(
   1752                             packageInfo.applicationInfo,
   1753                             IApplicationThread.BACKUP_MODE_INCREMENTAL);
   1754                     if (agent == null) {
   1755                         Slog.w(TAG, "Can't find backup agent for " + packageName);
   1756                         EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
   1757                                 "Restore agent missing");
   1758                         continue;
   1759                     }
   1760 
   1761                     // And then finally run the restore on this agent
   1762                     try {
   1763                         processOneRestore(packageInfo, metaInfo.versionCode, agent,
   1764                                 mNeedFullBackup);
   1765                         ++count;
   1766                     } finally {
   1767                         // unbind and tidy up even on timeout or failure, just in case
   1768                         mActivityManager.unbindBackupAgent(packageInfo.applicationInfo);
   1769 
   1770                         // The agent was probably running with a stub Application object,
   1771                         // which isn't a valid run mode for the main app logic.  Shut
   1772                         // down the app so that next time it's launched, it gets the
   1773                         // usual full initialization.  Note that this is only done for
   1774                         // full-system restores: when a single app has requested a restore,
   1775                         // it is explicitly not killed following that operation.
   1776                         if (mTargetPackage == null && (packageInfo.applicationInfo.flags
   1777                                 & ApplicationInfo.FLAG_KILL_AFTER_RESTORE) != 0) {
   1778                             if (DEBUG) Slog.d(TAG, "Restore complete, killing host process of "
   1779                                     + packageInfo.applicationInfo.processName);
   1780                             mActivityManager.killApplicationProcess(
   1781                                     packageInfo.applicationInfo.processName,
   1782                                     packageInfo.applicationInfo.uid);
   1783                         }
   1784                     }
   1785                 }
   1786 
   1787                 // if we get this far, report success to the observer
   1788                 error = 0;
   1789                 int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
   1790                 EventLog.writeEvent(EventLogTags.RESTORE_SUCCESS, count, millis);
   1791             } catch (Exception e) {
   1792                 Slog.e(TAG, "Error in restore thread", e);
   1793             } finally {
   1794                 if (DEBUG) Slog.d(TAG, "finishing restore mObserver=" + mObserver);
   1795 
   1796                 try {
   1797                     mTransport.finishRestore();
   1798                 } catch (RemoteException e) {
   1799                     Slog.e(TAG, "Error finishing restore", e);
   1800                 }
   1801 
   1802                 if (mObserver != null) {
   1803                     try {
   1804                         mObserver.restoreFinished(error);
   1805                     } catch (RemoteException e) {
   1806                         Slog.d(TAG, "Restore observer died at restoreFinished");
   1807                     }
   1808                 }
   1809 
   1810                 // If this was a restoreAll operation, record that this was our
   1811                 // ancestral dataset, as well as the set of apps that are possibly
   1812                 // restoreable from the dataset
   1813                 if (mTargetPackage == null && pmAgent != null) {
   1814                     mAncestralPackages = pmAgent.getRestoredPackages();
   1815                     mAncestralToken = mToken;
   1816                     writeRestoreTokens();
   1817                 }
   1818 
   1819                 // We must under all circumstances tell the Package Manager to
   1820                 // proceed with install notifications if it's waiting for us.
   1821                 if (mPmToken > 0) {
   1822                     if (DEBUG) Slog.v(TAG, "finishing PM token " + mPmToken);
   1823                     try {
   1824                         mPackageManagerBinder.finishPackageInstall(mPmToken);
   1825                     } catch (RemoteException e) { /* can't happen */ }
   1826                 }
   1827 
   1828                 // done; we can finally release the wakelock
   1829                 mWakelock.release();
   1830             }
   1831         }
   1832 
   1833         // Do the guts of a restore of one application, using mTransport.getRestoreData().
   1834         void processOneRestore(PackageInfo app, int appVersionCode, IBackupAgent agent,
   1835                 boolean needFullBackup) {
   1836             // !!! TODO: actually run the restore through mTransport
   1837             final String packageName = app.packageName;
   1838 
   1839             if (DEBUG) Slog.d(TAG, "processOneRestore packageName=" + packageName);
   1840 
   1841             // !!! TODO: get the dirs from the transport
   1842             File backupDataName = new File(mDataDir, packageName + ".restore");
   1843             File newStateName = new File(mStateDir, packageName + ".new");
   1844             File savedStateName = new File(mStateDir, packageName);
   1845 
   1846             ParcelFileDescriptor backupData = null;
   1847             ParcelFileDescriptor newState = null;
   1848 
   1849             int token = mTokenGenerator.nextInt();
   1850             try {
   1851                 // Run the transport's restore pass
   1852                 backupData = ParcelFileDescriptor.open(backupDataName,
   1853                             ParcelFileDescriptor.MODE_READ_WRITE |
   1854                             ParcelFileDescriptor.MODE_CREATE |
   1855                             ParcelFileDescriptor.MODE_TRUNCATE);
   1856 
   1857                 if (mTransport.getRestoreData(backupData) != BackupConstants.TRANSPORT_OK) {
   1858                     Slog.e(TAG, "Error getting restore data for " + packageName);
   1859                     EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
   1860                     return;
   1861                 }
   1862 
   1863                 // Okay, we have the data.  Now have the agent do the restore.
   1864                 backupData.close();
   1865                 backupData = ParcelFileDescriptor.open(backupDataName,
   1866                             ParcelFileDescriptor.MODE_READ_ONLY);
   1867 
   1868                 newState = ParcelFileDescriptor.open(newStateName,
   1869                             ParcelFileDescriptor.MODE_READ_WRITE |
   1870                             ParcelFileDescriptor.MODE_CREATE |
   1871                             ParcelFileDescriptor.MODE_TRUNCATE);
   1872 
   1873                 // Kick off the restore, checking for hung agents
   1874                 prepareOperationTimeout(token, TIMEOUT_RESTORE_INTERVAL);
   1875                 agent.doRestore(backupData, appVersionCode, newState, token, mBackupManagerBinder);
   1876                 boolean success = waitUntilOperationComplete(token);
   1877 
   1878                 if (!success) {
   1879                     throw new RuntimeException("restore timeout");
   1880                 }
   1881 
   1882                 // if everything went okay, remember the recorded state now
   1883                 //
   1884                 // !!! TODO: the restored data should be migrated on the server
   1885                 // side into the current dataset.  In that case the new state file
   1886                 // we just created would reflect the data already extant in the
   1887                 // backend, so there'd be nothing more to do.  Until that happens,
   1888                 // however, we need to make sure that we record the data to the
   1889                 // current backend dataset.  (Yes, this means shipping the data over
   1890                 // the wire in both directions.  That's bad, but consistency comes
   1891                 // first, then efficiency.)  Once we introduce server-side data
   1892                 // migration to the newly-restored device's dataset, we will change
   1893                 // the following from a discard of the newly-written state to the
   1894                 // "correct" operation of renaming into the canonical state blob.
   1895                 newStateName.delete();                      // TODO: remove; see above comment
   1896                 //newStateName.renameTo(savedStateName);    // TODO: replace with this
   1897 
   1898                 int size = (int) backupDataName.length();
   1899                 EventLog.writeEvent(EventLogTags.RESTORE_PACKAGE, packageName, size);
   1900             } catch (Exception e) {
   1901                 Slog.e(TAG, "Error restoring data for " + packageName, e);
   1902                 EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName, e.toString());
   1903 
   1904                 // If the agent fails restore, it might have put the app's data
   1905                 // into an incoherent state.  For consistency we wipe its data
   1906                 // again in this case before propagating the exception
   1907                 clearApplicationDataSynchronous(packageName);
   1908             } finally {
   1909                 backupDataName.delete();
   1910                 try { if (backupData != null) backupData.close(); } catch (IOException e) {}
   1911                 try { if (newState != null) newState.close(); } catch (IOException e) {}
   1912                 backupData = newState = null;
   1913                 mCurrentOperations.delete(token);
   1914 
   1915                 // If we know a priori that we'll need to perform a full post-restore backup
   1916                 // pass, clear the new state file data.  This means we're discarding work that
   1917                 // was just done by the app's agent, but this way the agent doesn't need to
   1918                 // take any special action based on global device state.
   1919                 if (needFullBackup) {
   1920                     newStateName.delete();
   1921                 }
   1922             }
   1923         }
   1924     }
   1925 
   1926     class PerformClearTask implements Runnable {
   1927         IBackupTransport mTransport;
   1928         PackageInfo mPackage;
   1929 
   1930         PerformClearTask(IBackupTransport transport, PackageInfo packageInfo) {
   1931             mTransport = transport;
   1932             mPackage = packageInfo;
   1933         }
   1934 
   1935         public void run() {
   1936             try {
   1937                 // Clear the on-device backup state to ensure a full backup next time
   1938                 File stateDir = new File(mBaseStateDir, mTransport.transportDirName());
   1939                 File stateFile = new File(stateDir, mPackage.packageName);
   1940                 stateFile.delete();
   1941 
   1942                 // Tell the transport to remove all the persistent storage for the app
   1943                 // TODO - need to handle failures
   1944                 mTransport.clearBackupData(mPackage);
   1945             } catch (RemoteException e) {
   1946                 // can't happen; the transport is local
   1947             } finally {
   1948                 try {
   1949                     // TODO - need to handle failures
   1950                     mTransport.finishBackup();
   1951                 } catch (RemoteException e) {
   1952                     // can't happen; the transport is local
   1953                 }
   1954 
   1955                 // Last but not least, release the cpu
   1956                 mWakelock.release();
   1957             }
   1958         }
   1959     }
   1960 
   1961     class PerformInitializeTask implements Runnable {
   1962         HashSet<String> mQueue;
   1963 
   1964         PerformInitializeTask(HashSet<String> transportNames) {
   1965             mQueue = transportNames;
   1966         }
   1967 
   1968         public void run() {
   1969             try {
   1970                 for (String transportName : mQueue) {
   1971                     IBackupTransport transport = getTransport(transportName);
   1972                     if (transport == null) {
   1973                         Slog.e(TAG, "Requested init for " + transportName + " but not found");
   1974                         continue;
   1975                     }
   1976 
   1977                     Slog.i(TAG, "Initializing (wiping) backup transport storage: " + transportName);
   1978                     EventLog.writeEvent(EventLogTags.BACKUP_START, transport.transportDirName());
   1979                     long startRealtime = SystemClock.elapsedRealtime();
   1980                     int status = transport.initializeDevice();
   1981 
   1982                     if (status == BackupConstants.TRANSPORT_OK) {
   1983                         status = transport.finishBackup();
   1984                     }
   1985 
   1986                     // Okay, the wipe really happened.  Clean up our local bookkeeping.
   1987                     if (status == BackupConstants.TRANSPORT_OK) {
   1988                         Slog.i(TAG, "Device init successful");
   1989                         int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
   1990                         EventLog.writeEvent(EventLogTags.BACKUP_INITIALIZE);
   1991                         resetBackupState(new File(mBaseStateDir, transport.transportDirName()));
   1992                         EventLog.writeEvent(EventLogTags.BACKUP_SUCCESS, 0, millis);
   1993                         synchronized (mQueueLock) {
   1994                             recordInitPendingLocked(false, transportName);
   1995                         }
   1996                     } else {
   1997                         // If this didn't work, requeue this one and try again
   1998                         // after a suitable interval
   1999                         Slog.e(TAG, "Transport error in initializeDevice()");
   2000                         EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, "(initialize)");
   2001                         synchronized (mQueueLock) {
   2002                             recordInitPendingLocked(true, transportName);
   2003                         }
   2004                         // do this via another alarm to make sure of the wakelock states
   2005                         long delay = transport.requestBackupTime();
   2006                         if (DEBUG) Slog.w(TAG, "init failed on "
   2007                                 + transportName + " resched in " + delay);
   2008                         mAlarmManager.set(AlarmManager.RTC_WAKEUP,
   2009                                 System.currentTimeMillis() + delay, mRunInitIntent);
   2010                     }
   2011                 }
   2012             } catch (RemoteException e) {
   2013                 // can't happen; the transports are local
   2014             } catch (Exception e) {
   2015                 Slog.e(TAG, "Unexpected error performing init", e);
   2016             } finally {
   2017                 // Done; release the wakelock
   2018                 mWakelock.release();
   2019             }
   2020         }
   2021     }
   2022 
   2023     private void dataChangedImpl(String packageName) {
   2024         HashSet<ApplicationInfo> targets = dataChangedTargets(packageName);
   2025         dataChangedImpl(packageName, targets);
   2026     }
   2027 
   2028     private void dataChangedImpl(String packageName, HashSet<ApplicationInfo> targets) {
   2029         // Record that we need a backup pass for the caller.  Since multiple callers
   2030         // may share a uid, we need to note all candidates within that uid and schedule
   2031         // a backup pass for each of them.
   2032         EventLog.writeEvent(EventLogTags.BACKUP_DATA_CHANGED, packageName);
   2033 
   2034         if (targets == null) {
   2035             Slog.w(TAG, "dataChanged but no participant pkg='" + packageName + "'"
   2036                    + " uid=" + Binder.getCallingUid());
   2037             return;
   2038         }
   2039 
   2040         synchronized (mQueueLock) {
   2041             // Note that this client has made data changes that need to be backed up
   2042             for (ApplicationInfo app : targets) {
   2043                 // validate the caller-supplied package name against the known set of
   2044                 // packages associated with this uid
   2045                 if (app.packageName.equals(packageName)) {
   2046                     // Add the caller to the set of pending backups.  If there is
   2047                     // one already there, then overwrite it, but no harm done.
   2048                     BackupRequest req = new BackupRequest(app, false);
   2049                     if (mPendingBackups.put(app, req) == null) {
   2050                         // Journal this request in case of crash.  The put()
   2051                         // operation returned null when this package was not already
   2052                         // in the set; we want to avoid touching the disk redundantly.
   2053                         writeToJournalLocked(packageName);
   2054 
   2055                         if (DEBUG) {
   2056                             int numKeys = mPendingBackups.size();
   2057                             Slog.d(TAG, "Now awaiting backup for " + numKeys + " participants:");
   2058                             for (BackupRequest b : mPendingBackups.values()) {
   2059                                 Slog.d(TAG, "    + " + b + " agent=" + b.appInfo.backupAgentName);
   2060                             }
   2061                         }
   2062                     }
   2063                 }
   2064             }
   2065         }
   2066     }
   2067 
   2068     // Note: packageName is currently unused, but may be in the future
   2069     private HashSet<ApplicationInfo> dataChangedTargets(String packageName) {
   2070         // If the caller does not hold the BACKUP permission, it can only request a
   2071         // backup of its own data.
   2072         if ((mContext.checkPermission(android.Manifest.permission.BACKUP, Binder.getCallingPid(),
   2073                 Binder.getCallingUid())) == PackageManager.PERMISSION_DENIED) {
   2074             synchronized (mBackupParticipants) {
   2075                 return mBackupParticipants.get(Binder.getCallingUid());
   2076             }
   2077         }
   2078 
   2079         // a caller with full permission can ask to back up any participating app
   2080         // !!! TODO: allow backup of ANY app?
   2081         HashSet<ApplicationInfo> targets = new HashSet<ApplicationInfo>();
   2082         synchronized (mBackupParticipants) {
   2083             int N = mBackupParticipants.size();
   2084             for (int i = 0; i < N; i++) {
   2085                 HashSet<ApplicationInfo> s = mBackupParticipants.valueAt(i);
   2086                 if (s != null) {
   2087                     targets.addAll(s);
   2088                 }
   2089             }
   2090         }
   2091         return targets;
   2092     }
   2093 
   2094     private void writeToJournalLocked(String str) {
   2095         RandomAccessFile out = null;
   2096         try {
   2097             if (mJournal == null) mJournal = File.createTempFile("journal", null, mJournalDir);
   2098             out = new RandomAccessFile(mJournal, "rws");
   2099             out.seek(out.length());
   2100             out.writeUTF(str);
   2101         } catch (IOException e) {
   2102             Slog.e(TAG, "Can't write " + str + " to backup journal", e);
   2103             mJournal = null;
   2104         } finally {
   2105             try { if (out != null) out.close(); } catch (IOException e) {}
   2106         }
   2107     }
   2108 
   2109     // ----- IBackupManager binder interface -----
   2110 
   2111     public void dataChanged(final String packageName) {
   2112         final HashSet<ApplicationInfo> targets = dataChangedTargets(packageName);
   2113         if (targets == null) {
   2114             Slog.w(TAG, "dataChanged but no participant pkg='" + packageName + "'"
   2115                    + " uid=" + Binder.getCallingUid());
   2116             return;
   2117         }
   2118 
   2119         mBackupHandler.post(new Runnable() {
   2120                 public void run() {
   2121                     dataChangedImpl(packageName, targets);
   2122                 }
   2123             });
   2124     }
   2125 
   2126     // Clear the given package's backup data from the current transport
   2127     public void clearBackupData(String packageName) {
   2128         if (DEBUG) Slog.v(TAG, "clearBackupData() of " + packageName);
   2129         PackageInfo info;
   2130         try {
   2131             info = mPackageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
   2132         } catch (NameNotFoundException e) {
   2133             Slog.d(TAG, "No such package '" + packageName + "' - not clearing backup data");
   2134             return;
   2135         }
   2136 
   2137         // If the caller does not hold the BACKUP permission, it can only request a
   2138         // wipe of its own backed-up data.
   2139         HashSet<ApplicationInfo> apps;
   2140         if ((mContext.checkPermission(android.Manifest.permission.BACKUP, Binder.getCallingPid(),
   2141                 Binder.getCallingUid())) == PackageManager.PERMISSION_DENIED) {
   2142             apps = mBackupParticipants.get(Binder.getCallingUid());
   2143         } else {
   2144             // a caller with full permission can ask to back up any participating app
   2145             // !!! TODO: allow data-clear of ANY app?
   2146             if (DEBUG) Slog.v(TAG, "Privileged caller, allowing clear of other apps");
   2147             apps = new HashSet<ApplicationInfo>();
   2148             int N = mBackupParticipants.size();
   2149             for (int i = 0; i < N; i++) {
   2150                 HashSet<ApplicationInfo> s = mBackupParticipants.valueAt(i);
   2151                 if (s != null) {
   2152                     apps.addAll(s);
   2153                 }
   2154             }
   2155         }
   2156 
   2157         // now find the given package in the set of candidate apps
   2158         for (ApplicationInfo app : apps) {
   2159             if (app.packageName.equals(packageName)) {
   2160                 if (DEBUG) Slog.v(TAG, "Found the app - running clear process");
   2161                 // found it; fire off the clear request
   2162                 synchronized (mQueueLock) {
   2163                     long oldId = Binder.clearCallingIdentity();
   2164                     mWakelock.acquire();
   2165                     Message msg = mBackupHandler.obtainMessage(MSG_RUN_CLEAR,
   2166                             new ClearParams(getTransport(mCurrentTransport), info));
   2167                     mBackupHandler.sendMessage(msg);
   2168                     Binder.restoreCallingIdentity(oldId);
   2169                 }
   2170                 break;
   2171             }
   2172         }
   2173     }
   2174 
   2175     // Run a backup pass immediately for any applications that have declared
   2176     // that they have pending updates.
   2177     public void backupNow() {
   2178         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "backupNow");
   2179 
   2180         if (DEBUG) Slog.v(TAG, "Scheduling immediate backup pass");
   2181         synchronized (mQueueLock) {
   2182             // Because the alarms we are using can jitter, and we want an *immediate*
   2183             // backup pass to happen, we restart the timer beginning with "next time,"
   2184             // then manually fire the backup trigger intent ourselves.
   2185             startBackupAlarmsLocked(BACKUP_INTERVAL);
   2186             try {
   2187                 mRunBackupIntent.send();
   2188             } catch (PendingIntent.CanceledException e) {
   2189                 // should never happen
   2190                 Slog.e(TAG, "run-backup intent cancelled!");
   2191             }
   2192         }
   2193     }
   2194 
   2195     // Enable/disable the backup service
   2196     public void setBackupEnabled(boolean enable) {
   2197         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   2198                 "setBackupEnabled");
   2199 
   2200         Slog.i(TAG, "Backup enabled => " + enable);
   2201 
   2202         boolean wasEnabled = mEnabled;
   2203         synchronized (this) {
   2204             Settings.Secure.putInt(mContext.getContentResolver(),
   2205                     Settings.Secure.BACKUP_ENABLED, enable ? 1 : 0);
   2206             mEnabled = enable;
   2207         }
   2208 
   2209         synchronized (mQueueLock) {
   2210             if (enable && !wasEnabled && mProvisioned) {
   2211                 // if we've just been enabled, start scheduling backup passes
   2212                 startBackupAlarmsLocked(BACKUP_INTERVAL);
   2213             } else if (!enable) {
   2214                 // No longer enabled, so stop running backups
   2215                 if (DEBUG) Slog.i(TAG, "Opting out of backup");
   2216 
   2217                 mAlarmManager.cancel(mRunBackupIntent);
   2218 
   2219                 // This also constitutes an opt-out, so we wipe any data for
   2220                 // this device from the backend.  We start that process with
   2221                 // an alarm in order to guarantee wakelock states.
   2222                 if (wasEnabled && mProvisioned) {
   2223                     // NOTE: we currently flush every registered transport, not just
   2224                     // the currently-active one.
   2225                     HashSet<String> allTransports;
   2226                     synchronized (mTransports) {
   2227                         allTransports = new HashSet<String>(mTransports.keySet());
   2228                     }
   2229                     // build the set of transports for which we are posting an init
   2230                     for (String transport : allTransports) {
   2231                         recordInitPendingLocked(true, transport);
   2232                     }
   2233                     mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
   2234                             mRunInitIntent);
   2235                 }
   2236             }
   2237         }
   2238     }
   2239 
   2240     // Enable/disable automatic restore of app data at install time
   2241     public void setAutoRestore(boolean doAutoRestore) {
   2242         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   2243         "setBackupEnabled");
   2244 
   2245         Slog.i(TAG, "Auto restore => " + doAutoRestore);
   2246 
   2247         synchronized (this) {
   2248             Settings.Secure.putInt(mContext.getContentResolver(),
   2249                     Settings.Secure.BACKUP_AUTO_RESTORE, doAutoRestore ? 1 : 0);
   2250             mAutoRestore = doAutoRestore;
   2251         }
   2252     }
   2253 
   2254     // Mark the backup service as having been provisioned
   2255     public void setBackupProvisioned(boolean available) {
   2256         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   2257                 "setBackupProvisioned");
   2258 
   2259         boolean wasProvisioned = mProvisioned;
   2260         synchronized (this) {
   2261             Settings.Secure.putInt(mContext.getContentResolver(),
   2262                     Settings.Secure.BACKUP_PROVISIONED, available ? 1 : 0);
   2263             mProvisioned = available;
   2264         }
   2265 
   2266         synchronized (mQueueLock) {
   2267             if (available && !wasProvisioned && mEnabled) {
   2268                 // we're now good to go, so start the backup alarms
   2269                 startBackupAlarmsLocked(FIRST_BACKUP_INTERVAL);
   2270             } else if (!available) {
   2271                 // No longer enabled, so stop running backups
   2272                 Slog.w(TAG, "Backup service no longer provisioned");
   2273                 mAlarmManager.cancel(mRunBackupIntent);
   2274             }
   2275         }
   2276     }
   2277 
   2278     private void startBackupAlarmsLocked(long delayBeforeFirstBackup) {
   2279         // We used to use setInexactRepeating(), but that may be linked to
   2280         // backups running at :00 more often than not, creating load spikes.
   2281         // Schedule at an exact time for now, and also add a bit of "fuzz".
   2282 
   2283         Random random = new Random();
   2284         long when = System.currentTimeMillis() + delayBeforeFirstBackup +
   2285                 random.nextInt(FUZZ_MILLIS);
   2286         mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, when,
   2287                 BACKUP_INTERVAL + random.nextInt(FUZZ_MILLIS), mRunBackupIntent);
   2288         mNextBackupPass = when;
   2289     }
   2290 
   2291     // Report whether the backup mechanism is currently enabled
   2292     public boolean isBackupEnabled() {
   2293         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "isBackupEnabled");
   2294         return mEnabled;    // no need to synchronize just to read it
   2295     }
   2296 
   2297     // Report the name of the currently active transport
   2298     public String getCurrentTransport() {
   2299         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   2300                 "getCurrentTransport");
   2301         if (DEBUG) Slog.v(TAG, "... getCurrentTransport() returning " + mCurrentTransport);
   2302         return mCurrentTransport;
   2303     }
   2304 
   2305     // Report all known, available backup transports
   2306     public String[] listAllTransports() {
   2307         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "listAllTransports");
   2308 
   2309         String[] list = null;
   2310         ArrayList<String> known = new ArrayList<String>();
   2311         for (Map.Entry<String, IBackupTransport> entry : mTransports.entrySet()) {
   2312             if (entry.getValue() != null) {
   2313                 known.add(entry.getKey());
   2314             }
   2315         }
   2316 
   2317         if (known.size() > 0) {
   2318             list = new String[known.size()];
   2319             known.toArray(list);
   2320         }
   2321         return list;
   2322     }
   2323 
   2324     // Select which transport to use for the next backup operation.  If the given
   2325     // name is not one of the available transports, no action is taken and the method
   2326     // returns null.
   2327     public String selectBackupTransport(String transport) {
   2328         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "selectBackupTransport");
   2329 
   2330         synchronized (mTransports) {
   2331             String prevTransport = null;
   2332             if (mTransports.get(transport) != null) {
   2333                 prevTransport = mCurrentTransport;
   2334                 mCurrentTransport = transport;
   2335                 Settings.Secure.putString(mContext.getContentResolver(),
   2336                         Settings.Secure.BACKUP_TRANSPORT, transport);
   2337                 Slog.v(TAG, "selectBackupTransport() set " + mCurrentTransport
   2338                         + " returning " + prevTransport);
   2339             } else {
   2340                 Slog.w(TAG, "Attempt to select unavailable transport " + transport);
   2341             }
   2342             return prevTransport;
   2343         }
   2344     }
   2345 
   2346     // Callback: a requested backup agent has been instantiated.  This should only
   2347     // be called from the Activity Manager.
   2348     public void agentConnected(String packageName, IBinder agentBinder) {
   2349         synchronized(mAgentConnectLock) {
   2350             if (Binder.getCallingUid() == Process.SYSTEM_UID) {
   2351                 Slog.d(TAG, "agentConnected pkg=" + packageName + " agent=" + agentBinder);
   2352                 IBackupAgent agent = IBackupAgent.Stub.asInterface(agentBinder);
   2353                 mConnectedAgent = agent;
   2354                 mConnecting = false;
   2355             } else {
   2356                 Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
   2357                         + " claiming agent connected");
   2358             }
   2359             mAgentConnectLock.notifyAll();
   2360         }
   2361     }
   2362 
   2363     // Callback: a backup agent has failed to come up, or has unexpectedly quit.
   2364     // If the agent failed to come up in the first place, the agentBinder argument
   2365     // will be null.  This should only be called from the Activity Manager.
   2366     public void agentDisconnected(String packageName) {
   2367         // TODO: handle backup being interrupted
   2368         synchronized(mAgentConnectLock) {
   2369             if (Binder.getCallingUid() == Process.SYSTEM_UID) {
   2370                 mConnectedAgent = null;
   2371                 mConnecting = false;
   2372             } else {
   2373                 Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
   2374                         + " claiming agent disconnected");
   2375             }
   2376             mAgentConnectLock.notifyAll();
   2377         }
   2378     }
   2379 
   2380     // An application being installed will need a restore pass, then the Package Manager
   2381     // will need to be told when the restore is finished.
   2382     public void restoreAtInstall(String packageName, int token) {
   2383         if (Binder.getCallingUid() != Process.SYSTEM_UID) {
   2384             Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
   2385                     + " attemping install-time restore");
   2386             return;
   2387         }
   2388 
   2389         long restoreSet = getAvailableRestoreToken(packageName);
   2390         if (DEBUG) Slog.v(TAG, "restoreAtInstall pkg=" + packageName
   2391                 + " token=" + Integer.toHexString(token));
   2392 
   2393         if (mAutoRestore && mProvisioned && restoreSet != 0) {
   2394             // okay, we're going to attempt a restore of this package from this restore set.
   2395             // The eventual message back into the Package Manager to run the post-install
   2396             // steps for 'token' will be issued from the restore handling code.
   2397 
   2398             // We can use a synthetic PackageInfo here because:
   2399             //   1. We know it's valid, since the Package Manager supplied the name
   2400             //   2. Only the packageName field will be used by the restore code
   2401             PackageInfo pkg = new PackageInfo();
   2402             pkg.packageName = packageName;
   2403 
   2404             mWakelock.acquire();
   2405             Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
   2406             msg.obj = new RestoreParams(getTransport(mCurrentTransport), null,
   2407                     restoreSet, pkg, token, true);
   2408             mBackupHandler.sendMessage(msg);
   2409         } else {
   2410             // Auto-restore disabled or no way to attempt a restore; just tell the Package
   2411             // Manager to proceed with the post-install handling for this package.
   2412             if (DEBUG) Slog.v(TAG, "No restore set -- skipping restore");
   2413             try {
   2414                 mPackageManagerBinder.finishPackageInstall(token);
   2415             } catch (RemoteException e) { /* can't happen */ }
   2416         }
   2417     }
   2418 
   2419     // Hand off a restore session
   2420     public IRestoreSession beginRestoreSession(String packageName, String transport) {
   2421         if (DEBUG) Slog.v(TAG, "beginRestoreSession: pkg=" + packageName
   2422                 + " transport=" + transport);
   2423 
   2424         boolean needPermission = true;
   2425         if (transport == null) {
   2426             transport = mCurrentTransport;
   2427 
   2428             if (packageName != null) {
   2429                 PackageInfo app = null;
   2430                 try {
   2431                     app = mPackageManager.getPackageInfo(packageName, 0);
   2432                 } catch (NameNotFoundException nnf) {
   2433                     Slog.w(TAG, "Asked to restore nonexistent pkg " + packageName);
   2434                     throw new IllegalArgumentException("Package " + packageName + " not found");
   2435                 }
   2436 
   2437                 if (app.applicationInfo.uid == Binder.getCallingUid()) {
   2438                     // So: using the current active transport, and the caller has asked
   2439                     // that its own package will be restored.  In this narrow use case
   2440                     // we do not require the caller to hold the permission.
   2441                     needPermission = false;
   2442                 }
   2443             }
   2444         }
   2445 
   2446         if (needPermission) {
   2447             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   2448                     "beginRestoreSession");
   2449         } else {
   2450             if (DEBUG) Slog.d(TAG, "restoring self on current transport; no permission needed");
   2451         }
   2452 
   2453         synchronized(this) {
   2454             if (mActiveRestoreSession != null) {
   2455                 Slog.d(TAG, "Restore session requested but one already active");
   2456                 return null;
   2457             }
   2458             mActiveRestoreSession = new ActiveRestoreSession(packageName, transport);
   2459         }
   2460         return mActiveRestoreSession;
   2461     }
   2462 
   2463     // Note that a currently-active backup agent has notified us that it has
   2464     // completed the given outstanding asynchronous backup/restore operation.
   2465     public void opComplete(int token) {
   2466         synchronized (mCurrentOpLock) {
   2467             if (DEBUG) Slog.v(TAG, "opComplete: " + Integer.toHexString(token));
   2468             mCurrentOperations.put(token, OP_ACKNOWLEDGED);
   2469             mCurrentOpLock.notifyAll();
   2470         }
   2471     }
   2472 
   2473     // ----- Restore session -----
   2474 
   2475     class ActiveRestoreSession extends IRestoreSession.Stub {
   2476         private static final String TAG = "RestoreSession";
   2477 
   2478         private String mPackageName;
   2479         private IBackupTransport mRestoreTransport = null;
   2480         RestoreSet[] mRestoreSets = null;
   2481 
   2482         ActiveRestoreSession(String packageName, String transport) {
   2483             mPackageName = packageName;
   2484             mRestoreTransport = getTransport(transport);
   2485         }
   2486 
   2487         // --- Binder interface ---
   2488         public synchronized int getAvailableRestoreSets(IRestoreObserver observer) {
   2489             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   2490                     "getAvailableRestoreSets");
   2491             if (observer == null) {
   2492                 throw new IllegalArgumentException("Observer must not be null");
   2493             }
   2494 
   2495             long oldId = Binder.clearCallingIdentity();
   2496             try {
   2497                 if (mRestoreTransport == null) {
   2498                     Slog.w(TAG, "Null transport getting restore sets");
   2499                     return -1;
   2500                 }
   2501                 // spin off the transport request to our service thread
   2502                 mWakelock.acquire();
   2503                 Message msg = mBackupHandler.obtainMessage(MSG_RUN_GET_RESTORE_SETS,
   2504                         new RestoreGetSetsParams(mRestoreTransport, this, observer));
   2505                 mBackupHandler.sendMessage(msg);
   2506                 return 0;
   2507             } catch (Exception e) {
   2508                 Slog.e(TAG, "Error in getAvailableRestoreSets", e);
   2509                 return -1;
   2510             } finally {
   2511                 Binder.restoreCallingIdentity(oldId);
   2512             }
   2513         }
   2514 
   2515         public synchronized int restoreAll(long token, IRestoreObserver observer) {
   2516             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
   2517                     "performRestore");
   2518 
   2519             if (DEBUG) Slog.d(TAG, "restoreAll token=" + Long.toHexString(token)
   2520                     + " observer=" + observer);
   2521 
   2522             if (mRestoreTransport == null || mRestoreSets == null) {
   2523                 Slog.e(TAG, "Ignoring restoreAll() with no restore set");
   2524                 return -1;
   2525             }
   2526 
   2527             if (mPackageName != null) {
   2528                 Slog.e(TAG, "Ignoring restoreAll() on single-package session");
   2529                 return -1;
   2530             }
   2531 
   2532             synchronized (mQueueLock) {
   2533                 for (int i = 0; i < mRestoreSets.length; i++) {
   2534                     if (token == mRestoreSets[i].token) {
   2535                         long oldId = Binder.clearCallingIdentity();
   2536                         mWakelock.acquire();
   2537                         Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
   2538                         msg.obj = new RestoreParams(mRestoreTransport, observer, token, true);
   2539                         mBackupHandler.sendMessage(msg);
   2540                         Binder.restoreCallingIdentity(oldId);
   2541                         return 0;
   2542                     }
   2543                 }
   2544             }
   2545 
   2546             Slog.w(TAG, "Restore token " + Long.toHexString(token) + " not found");
   2547             return -1;
   2548         }
   2549 
   2550         public synchronized int restorePackage(String packageName, IRestoreObserver observer) {
   2551             if (DEBUG) Slog.v(TAG, "restorePackage pkg=" + packageName + " obs=" + observer);
   2552 
   2553             if (mPackageName != null) {
   2554                 if (! mPackageName.equals(packageName)) {
   2555                     Slog.e(TAG, "Ignoring attempt to restore pkg=" + packageName
   2556                             + " on session for package " + mPackageName);
   2557                     return -1;
   2558                 }
   2559             }
   2560 
   2561             PackageInfo app = null;
   2562             try {
   2563                 app = mPackageManager.getPackageInfo(packageName, 0);
   2564             } catch (NameNotFoundException nnf) {
   2565                 Slog.w(TAG, "Asked to restore nonexistent pkg " + packageName);
   2566                 return -1;
   2567             }
   2568 
   2569             // If the caller is not privileged and is not coming from the target
   2570             // app's uid, throw a permission exception back to the caller.
   2571             int perm = mContext.checkPermission(android.Manifest.permission.BACKUP,
   2572                     Binder.getCallingPid(), Binder.getCallingUid());
   2573             if ((perm == PackageManager.PERMISSION_DENIED) &&
   2574                     (app.applicationInfo.uid != Binder.getCallingUid())) {
   2575                 Slog.w(TAG, "restorePackage: bad packageName=" + packageName
   2576                         + " or calling uid=" + Binder.getCallingUid());
   2577                 throw new SecurityException("No permission to restore other packages");
   2578             }
   2579 
   2580             // If the package has no backup agent, we obviously cannot proceed
   2581             if (app.applicationInfo.backupAgentName == null) {
   2582                 Slog.w(TAG, "Asked to restore package " + packageName + " with no agent");
   2583                 return -1;
   2584             }
   2585 
   2586             // So far so good; we're allowed to try to restore this package.  Now
   2587             // check whether there is data for it in the current dataset, falling back
   2588             // to the ancestral dataset if not.
   2589             long token = getAvailableRestoreToken(packageName);
   2590 
   2591             // If we didn't come up with a place to look -- no ancestral dataset and
   2592             // the app has never been backed up from this device -- there's nothing
   2593             // to do but return failure.
   2594             if (token == 0) {
   2595                 if (DEBUG) Slog.w(TAG, "No data available for this package; not restoring");
   2596                 return -1;
   2597             }
   2598 
   2599             // Ready to go:  enqueue the restore request and claim success
   2600             long oldId = Binder.clearCallingIdentity();
   2601             mWakelock.acquire();
   2602             Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
   2603             msg.obj = new RestoreParams(mRestoreTransport, observer, token, app, 0, false);
   2604             mBackupHandler.sendMessage(msg);
   2605             Binder.restoreCallingIdentity(oldId);
   2606             return 0;
   2607         }
   2608 
   2609         public synchronized void endRestoreSession() {
   2610             if (DEBUG) Slog.d(TAG, "endRestoreSession");
   2611 
   2612             synchronized (this) {
   2613                 long oldId = Binder.clearCallingIdentity();
   2614                 try {
   2615                     if (mRestoreTransport != null) mRestoreTransport.finishRestore();
   2616                 } catch (Exception e) {
   2617                     Slog.e(TAG, "Error in finishRestore", e);
   2618                 } finally {
   2619                     mRestoreTransport = null;
   2620                     Binder.restoreCallingIdentity(oldId);
   2621                 }
   2622             }
   2623 
   2624             synchronized (BackupManagerService.this) {
   2625                 if (BackupManagerService.this.mActiveRestoreSession == this) {
   2626                     BackupManagerService.this.mActiveRestoreSession = null;
   2627                 } else {
   2628                     Slog.e(TAG, "ending non-current restore session");
   2629                 }
   2630             }
   2631         }
   2632     }
   2633 
   2634 
   2635     @Override
   2636     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   2637         synchronized (mQueueLock) {
   2638             pw.println("Backup Manager is " + (mEnabled ? "enabled" : "disabled")
   2639                     + " / " + (!mProvisioned ? "not " : "") + "provisioned / "
   2640                     + (this.mPendingInits.size() == 0 ? "not " : "") + "pending init");
   2641             pw.println("Auto-restore is " + (mAutoRestore ? "enabled" : "disabled"));
   2642             pw.println("Last backup pass: " + mLastBackupPass
   2643                     + " (now = " + System.currentTimeMillis() + ')');
   2644             pw.println("  next scheduled: " + mNextBackupPass);
   2645 
   2646             pw.println("Available transports:");
   2647             for (String t : listAllTransports()) {
   2648                 pw.println((t.equals(mCurrentTransport) ? "  * " : "    ") + t);
   2649                 try {
   2650                     File dir = new File(mBaseStateDir, getTransport(t).transportDirName());
   2651                     for (File f : dir.listFiles()) {
   2652                         pw.println("       " + f.getName() + " - " + f.length() + " state bytes");
   2653                     }
   2654                 } catch (RemoteException e) {
   2655                     Slog.e(TAG, "Error in transportDirName()", e);
   2656                     pw.println("        Error: " + e);
   2657                 }
   2658             }
   2659 
   2660             pw.println("Pending init: " + mPendingInits.size());
   2661             for (String s : mPendingInits) {
   2662                 pw.println("    " + s);
   2663             }
   2664 
   2665             int N = mBackupParticipants.size();
   2666             pw.println("Participants:");
   2667             for (int i=0; i<N; i++) {
   2668                 int uid = mBackupParticipants.keyAt(i);
   2669                 pw.print("  uid: ");
   2670                 pw.println(uid);
   2671                 HashSet<ApplicationInfo> participants = mBackupParticipants.valueAt(i);
   2672                 for (ApplicationInfo app: participants) {
   2673                     pw.println("    " + app.packageName);
   2674                 }
   2675             }
   2676 
   2677             pw.println("Ancestral packages: "
   2678                     + (mAncestralPackages == null ? "none" : mAncestralPackages.size()));
   2679             if (mAncestralPackages != null) {
   2680                 for (String pkg : mAncestralPackages) {
   2681                     pw.println("    " + pkg);
   2682                 }
   2683             }
   2684 
   2685             pw.println("Ever backed up: " + mEverStoredApps.size());
   2686             for (String pkg : mEverStoredApps) {
   2687                 pw.println("    " + pkg);
   2688             }
   2689 
   2690             pw.println("Pending backup: " + mPendingBackups.size());
   2691             for (BackupRequest req : mPendingBackups.values()) {
   2692                 pw.println("    " + req);
   2693             }
   2694         }
   2695     }
   2696 }
   2697