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