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