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