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