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