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