1 /* 2 * Copyright (C) 2017 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.backup; 18 19 import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND; 20 21 import static com.android.server.backup.internal.BackupHandler.MSG_BACKUP_OPERATION_TIMEOUT; 22 import static com.android.server.backup.internal.BackupHandler.MSG_FULL_CONFIRMATION_TIMEOUT; 23 import static com.android.server.backup.internal.BackupHandler.MSG_OP_COMPLETE; 24 import static com.android.server.backup.internal.BackupHandler.MSG_REQUEST_BACKUP; 25 import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_OPERATION_TIMEOUT; 26 import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_SESSION_TIMEOUT; 27 import static com.android.server.backup.internal.BackupHandler.MSG_RETRY_CLEAR; 28 import static com.android.server.backup.internal.BackupHandler.MSG_RUN_ADB_BACKUP; 29 import static com.android.server.backup.internal.BackupHandler.MSG_RUN_ADB_RESTORE; 30 import static com.android.server.backup.internal.BackupHandler.MSG_RUN_CLEAR; 31 import static com.android.server.backup.internal.BackupHandler.MSG_RUN_RESTORE; 32 import static com.android.server.backup.internal.BackupHandler.MSG_SCHEDULE_BACKUP_PACKAGE; 33 34 import android.annotation.Nullable; 35 import android.app.ActivityManager; 36 import android.app.AlarmManager; 37 import android.app.AppGlobals; 38 import android.app.IActivityManager; 39 import android.app.IBackupAgent; 40 import android.app.PendingIntent; 41 import android.app.backup.BackupManager; 42 import android.app.backup.BackupManagerMonitor; 43 import android.app.backup.FullBackup; 44 import android.app.backup.IBackupManager; 45 import android.app.backup.IBackupManagerMonitor; 46 import android.app.backup.IBackupObserver; 47 import android.app.backup.IFullBackupRestoreObserver; 48 import android.app.backup.IRestoreSession; 49 import android.app.backup.ISelectBackupTransportCallback; 50 import android.content.ActivityNotFoundException; 51 import android.content.BroadcastReceiver; 52 import android.content.ComponentName; 53 import android.content.ContentResolver; 54 import android.content.Context; 55 import android.content.Intent; 56 import android.content.IntentFilter; 57 import android.content.pm.ApplicationInfo; 58 import android.content.pm.IPackageManager; 59 import android.content.pm.PackageInfo; 60 import android.content.pm.PackageManager; 61 import android.content.pm.PackageManager.NameNotFoundException; 62 import android.database.ContentObserver; 63 import android.net.Uri; 64 import android.os.Binder; 65 import android.os.Bundle; 66 import android.os.Environment; 67 import android.os.Handler; 68 import android.os.HandlerThread; 69 import android.os.IBinder; 70 import android.os.Message; 71 import android.os.ParcelFileDescriptor; 72 import android.os.PowerManager; 73 import android.os.PowerManager.ServiceType; 74 import android.os.PowerSaveState; 75 import android.os.Process; 76 import android.os.RemoteException; 77 import android.os.SELinux; 78 import android.os.ServiceManager; 79 import android.os.SystemClock; 80 import android.os.Trace; 81 import android.os.UserHandle; 82 import android.os.storage.IStorageManager; 83 import android.os.storage.StorageManager; 84 import android.provider.Settings; 85 import android.text.TextUtils; 86 import android.util.ArraySet; 87 import android.util.AtomicFile; 88 import android.util.EventLog; 89 import android.util.Pair; 90 import android.util.Slog; 91 import android.util.SparseArray; 92 93 import com.android.internal.annotations.GuardedBy; 94 import com.android.internal.annotations.VisibleForTesting; 95 import com.android.internal.backup.IBackupTransport; 96 import com.android.internal.util.DumpUtils; 97 import com.android.internal.util.Preconditions; 98 import com.android.server.AppWidgetBackupBridge; 99 import com.android.server.EventLogTags; 100 import com.android.server.SystemConfig; 101 import com.android.server.SystemService; 102 import com.android.server.backup.fullbackup.FullBackupEntry; 103 import com.android.server.backup.fullbackup.PerformFullTransportBackupTask; 104 import com.android.server.backup.internal.BackupHandler; 105 import com.android.server.backup.internal.BackupRequest; 106 import com.android.server.backup.internal.ClearDataObserver; 107 import com.android.server.backup.internal.OnTaskFinishedListener; 108 import com.android.server.backup.internal.Operation; 109 import com.android.server.backup.internal.PerformInitializeTask; 110 import com.android.server.backup.internal.ProvisionedObserver; 111 import com.android.server.backup.internal.RunBackupReceiver; 112 import com.android.server.backup.internal.RunInitializeReceiver; 113 import com.android.server.backup.params.AdbBackupParams; 114 import com.android.server.backup.params.AdbParams; 115 import com.android.server.backup.params.AdbRestoreParams; 116 import com.android.server.backup.params.BackupParams; 117 import com.android.server.backup.params.ClearParams; 118 import com.android.server.backup.params.ClearRetryParams; 119 import com.android.server.backup.params.RestoreParams; 120 import com.android.server.backup.restore.ActiveRestoreSession; 121 import com.android.server.backup.restore.PerformUnifiedRestoreTask; 122 import com.android.server.backup.transport.TransportClient; 123 import com.android.server.backup.transport.TransportNotRegisteredException; 124 import com.android.server.backup.utils.AppBackupUtils; 125 import com.android.server.backup.utils.BackupManagerMonitorUtils; 126 import com.android.server.backup.utils.BackupObserverUtils; 127 import com.android.server.backup.utils.SparseArrayUtils; 128 129 import com.google.android.collect.Sets; 130 131 import java.io.BufferedInputStream; 132 import java.io.ByteArrayOutputStream; 133 import java.io.DataInputStream; 134 import java.io.DataOutputStream; 135 import java.io.File; 136 import java.io.FileDescriptor; 137 import java.io.FileInputStream; 138 import java.io.FileNotFoundException; 139 import java.io.FileOutputStream; 140 import java.io.IOException; 141 import java.io.PrintWriter; 142 import java.io.RandomAccessFile; 143 import java.security.SecureRandom; 144 import java.text.SimpleDateFormat; 145 import java.util.ArrayDeque; 146 import java.util.ArrayList; 147 import java.util.Arrays; 148 import java.util.Collections; 149 import java.util.Date; 150 import java.util.HashMap; 151 import java.util.HashSet; 152 import java.util.LinkedList; 153 import java.util.List; 154 import java.util.Queue; 155 import java.util.Random; 156 import java.util.Set; 157 import java.util.concurrent.CountDownLatch; 158 import java.util.concurrent.atomic.AtomicInteger; 159 160 public class BackupManagerService implements BackupManagerServiceInterface { 161 162 public static final String TAG = "BackupManagerService"; 163 public static final boolean DEBUG = true; 164 public static final boolean MORE_DEBUG = false; 165 public static final boolean DEBUG_SCHEDULING = MORE_DEBUG || true; 166 167 // File containing backup-enabled state. Contains a single byte; 168 // nonzero == enabled. File missing or contains a zero byte == disabled. 169 private static final String BACKUP_ENABLE_FILE = "backup_enabled"; 170 171 // System-private key used for backing up an app's widget state. Must 172 // begin with U+FFxx by convention (we reserve all keys starting 173 // with U+FF00 or higher for system use). 174 public static final String KEY_WIDGET_STATE = "\uffed\uffedwidget"; 175 176 // Name and current contents version of the full-backup manifest file 177 // 178 // Manifest version history: 179 // 180 // 1 : initial release 181 public static final String BACKUP_MANIFEST_FILENAME = "_manifest"; 182 public static final int BACKUP_MANIFEST_VERSION = 1; 183 184 // External archive format version history: 185 // 186 // 1 : initial release 187 // 2 : no format change per se; version bump to facilitate PBKDF2 version skew detection 188 // 3 : introduced "_meta" metadata file; no other format change per se 189 // 4 : added support for new device-encrypted storage locations 190 // 5 : added support for key-value packages 191 public static final int BACKUP_FILE_VERSION = 5; 192 public static final String BACKUP_FILE_HEADER_MAGIC = "ANDROID BACKUP\n"; 193 public static final String BACKUP_METADATA_FILENAME = "_meta"; 194 public static final int BACKUP_METADATA_VERSION = 1; 195 public static final int BACKUP_WIDGET_METADATA_TOKEN = 0x01FFED01; 196 197 private static final boolean COMPRESS_FULL_BACKUPS = true; // should be true in production 198 199 public static final String SETTINGS_PACKAGE = "com.android.providers.settings"; 200 public static final String SHARED_BACKUP_AGENT_PACKAGE = "com.android.sharedstoragebackup"; 201 private static final String SERVICE_ACTION_TRANSPORT_HOST = "android.backup.TRANSPORT_HOST"; 202 203 // Retry interval for clear/init when the transport is unavailable 204 private static final long TRANSPORT_RETRY_INTERVAL = 1 * AlarmManager.INTERVAL_HOUR; 205 206 public static final String RUN_BACKUP_ACTION = "android.app.backup.intent.RUN"; 207 public static final String RUN_INITIALIZE_ACTION = "android.app.backup.intent.INIT"; 208 public static final String BACKUP_FINISHED_ACTION = "android.intent.action.BACKUP_FINISHED"; 209 public static final String BACKUP_FINISHED_PACKAGE_EXTRA = "packageName"; 210 211 // Time delay for initialization operations that can be delayed so as not to consume too much CPU 212 // on bring-up and increase time-to-UI. 213 private static final long INITIALIZATION_DELAY_MILLIS = 3000; 214 215 // Timeout interval for deciding that a bind or clear-data has taken too long 216 private static final long TIMEOUT_INTERVAL = 10 * 1000; 217 218 // User confirmation timeout for a full backup/restore operation. It's this long in 219 // order to give them time to enter the backup password. 220 private static final long TIMEOUT_FULL_CONFIRMATION = 60 * 1000; 221 222 // If an app is busy when we want to do a full-data backup, how long to defer the retry. 223 // This is fuzzed, so there are two parameters; backoff_min + Rand[0, backoff_fuzz) 224 private static final long BUSY_BACKOFF_MIN_MILLIS = 1000 * 60 * 60; // one hour 225 private static final int BUSY_BACKOFF_FUZZ = 1000 * 60 * 60 * 2; // two hours 226 227 private BackupManagerConstants mConstants; 228 private final BackupAgentTimeoutParameters mAgentTimeoutParameters; 229 private Context mContext; 230 private PackageManager mPackageManager; 231 private IPackageManager mPackageManagerBinder; 232 private IActivityManager mActivityManager; 233 private PowerManager mPowerManager; 234 private AlarmManager mAlarmManager; 235 private IStorageManager mStorageManager; 236 237 private IBackupManager mBackupManagerBinder; 238 239 private final TransportManager mTransportManager; 240 241 private boolean mEnabled; // access to this is synchronized on 'this' 242 private boolean mProvisioned; 243 private boolean mAutoRestore; 244 private PowerManager.WakeLock mWakelock; 245 private BackupHandler mBackupHandler; 246 private PendingIntent mRunBackupIntent; 247 private PendingIntent mRunInitIntent; 248 private BroadcastReceiver mRunBackupReceiver; 249 private BroadcastReceiver mRunInitReceiver; 250 // map UIDs to the set of participating packages under that UID 251 private final SparseArray<HashSet<String>> mBackupParticipants 252 = new SparseArray<>(); 253 254 // Backups that we haven't started yet. Keys are package names. 255 private HashMap<String, BackupRequest> mPendingBackups 256 = new HashMap<>(); 257 258 // Pseudoname that we use for the Package Manager metadata "package" 259 public static final String PACKAGE_MANAGER_SENTINEL = "@pm@"; 260 261 // locking around the pending-backup management 262 private final Object mQueueLock = new Object(); 263 264 // The thread performing the sequence of queued backups binds to each app's agent 265 // in succession. Bind notifications are asynchronously delivered through the 266 // Activity Manager; use this lock object to signal when a requested binding has 267 // completed. 268 private final Object mAgentConnectLock = new Object(); 269 private IBackupAgent mConnectedAgent; 270 private volatile boolean mBackupRunning; 271 private volatile boolean mConnecting; 272 private volatile long mLastBackupPass; 273 274 // For debugging, we maintain a progress trace of operations during backup 275 public static final boolean DEBUG_BACKUP_TRACE = true; 276 private final List<String> mBackupTrace = new ArrayList<>(); 277 278 // A similar synchronization mechanism around clearing apps' data for restore 279 private final Object mClearDataLock = new Object(); 280 private volatile boolean mClearingData; 281 282 private final BackupPasswordManager mBackupPasswordManager; 283 284 // Time when we post the transport registration operation 285 private final long mRegisterTransportsRequestedTime; 286 287 @GuardedBy("mPendingRestores") 288 private boolean mIsRestoreInProgress; 289 @GuardedBy("mPendingRestores") 290 private final Queue<PerformUnifiedRestoreTask> mPendingRestores = new ArrayDeque<>(); 291 292 private ActiveRestoreSession mActiveRestoreSession; 293 294 // Watch the device provisioning operation during setup 295 private ContentObserver mProvisionedObserver; 296 297 // The published binder is actually to a singleton trampoline object that calls 298 // through to the proper code. This indirection lets us turn down the heavy 299 // implementation object on the fly without disturbing binders that have been 300 // cached elsewhere in the system. 301 static Trampoline sInstance; 302 303 static Trampoline getInstance() { 304 // Always constructed during system bringup, so no need to lazy-init 305 return sInstance; 306 } 307 308 public BackupManagerConstants getConstants() { 309 return mConstants; 310 } 311 312 public BackupAgentTimeoutParameters getAgentTimeoutParameters() { 313 return mAgentTimeoutParameters; 314 } 315 316 public Context getContext() { 317 return mContext; 318 } 319 320 public void setContext(Context context) { 321 mContext = context; 322 } 323 324 public PackageManager getPackageManager() { 325 return mPackageManager; 326 } 327 328 public void setPackageManager(PackageManager packageManager) { 329 mPackageManager = packageManager; 330 } 331 332 public IPackageManager getPackageManagerBinder() { 333 return mPackageManagerBinder; 334 } 335 336 public void setPackageManagerBinder(IPackageManager packageManagerBinder) { 337 mPackageManagerBinder = packageManagerBinder; 338 } 339 340 public IActivityManager getActivityManager() { 341 return mActivityManager; 342 } 343 344 public void setActivityManager(IActivityManager activityManager) { 345 mActivityManager = activityManager; 346 } 347 348 public AlarmManager getAlarmManager() { 349 return mAlarmManager; 350 } 351 352 public void setAlarmManager(AlarmManager alarmManager) { 353 mAlarmManager = alarmManager; 354 } 355 356 public void setBackupManagerBinder(IBackupManager backupManagerBinder) { 357 mBackupManagerBinder = backupManagerBinder; 358 } 359 360 public TransportManager getTransportManager() { 361 return mTransportManager; 362 } 363 364 public boolean isEnabled() { 365 return mEnabled; 366 } 367 368 public void setEnabled(boolean enabled) { 369 mEnabled = enabled; 370 } 371 372 public boolean isProvisioned() { 373 return mProvisioned; 374 } 375 376 public void setProvisioned(boolean provisioned) { 377 mProvisioned = provisioned; 378 } 379 380 public PowerManager.WakeLock getWakelock() { 381 return mWakelock; 382 } 383 384 public void setWakelock(PowerManager.WakeLock wakelock) { 385 mWakelock = wakelock; 386 } 387 388 public Handler getBackupHandler() { 389 return mBackupHandler; 390 } 391 392 public void setBackupHandler(BackupHandler backupHandler) { 393 mBackupHandler = backupHandler; 394 } 395 396 public PendingIntent getRunInitIntent() { 397 return mRunInitIntent; 398 } 399 400 public void setRunInitIntent(PendingIntent runInitIntent) { 401 mRunInitIntent = runInitIntent; 402 } 403 404 public HashMap<String, BackupRequest> getPendingBackups() { 405 return mPendingBackups; 406 } 407 408 public void setPendingBackups( 409 HashMap<String, BackupRequest> pendingBackups) { 410 mPendingBackups = pendingBackups; 411 } 412 413 public Object getQueueLock() { 414 return mQueueLock; 415 } 416 417 public boolean isBackupRunning() { 418 return mBackupRunning; 419 } 420 421 public void setBackupRunning(boolean backupRunning) { 422 mBackupRunning = backupRunning; 423 } 424 425 public long getLastBackupPass() { 426 return mLastBackupPass; 427 } 428 429 public void setLastBackupPass(long lastBackupPass) { 430 mLastBackupPass = lastBackupPass; 431 } 432 433 public Object getClearDataLock() { 434 return mClearDataLock; 435 } 436 437 public boolean isClearingData() { 438 return mClearingData; 439 } 440 441 public void setClearingData(boolean clearingData) { 442 mClearingData = clearingData; 443 } 444 445 public boolean isRestoreInProgress() { 446 return mIsRestoreInProgress; 447 } 448 449 public void setRestoreInProgress(boolean restoreInProgress) { 450 mIsRestoreInProgress = restoreInProgress; 451 } 452 453 public Queue<PerformUnifiedRestoreTask> getPendingRestores() { 454 return mPendingRestores; 455 } 456 457 public ActiveRestoreSession getActiveRestoreSession() { 458 return mActiveRestoreSession; 459 } 460 461 public void setActiveRestoreSession( 462 ActiveRestoreSession activeRestoreSession) { 463 mActiveRestoreSession = activeRestoreSession; 464 } 465 466 public SparseArray<Operation> getCurrentOperations() { 467 return mCurrentOperations; 468 } 469 470 public Object getCurrentOpLock() { 471 return mCurrentOpLock; 472 } 473 474 public SparseArray<AdbParams> getAdbBackupRestoreConfirmations() { 475 return mAdbBackupRestoreConfirmations; 476 } 477 478 public File getBaseStateDir() { 479 return mBaseStateDir; 480 } 481 482 public void setBaseStateDir(File baseStateDir) { 483 mBaseStateDir = baseStateDir; 484 } 485 486 public File getDataDir() { 487 return mDataDir; 488 } 489 490 public void setDataDir(File dataDir) { 491 mDataDir = dataDir; 492 } 493 494 public DataChangedJournal getJournal() { 495 return mJournal; 496 } 497 498 public void setJournal(@Nullable DataChangedJournal journal) { 499 mJournal = journal; 500 } 501 502 public SecureRandom getRng() { 503 return mRng; 504 } 505 506 public Set<String> getAncestralPackages() { 507 return mAncestralPackages; 508 } 509 510 public void setAncestralPackages(Set<String> ancestralPackages) { 511 mAncestralPackages = ancestralPackages; 512 } 513 514 public long getAncestralToken() { 515 return mAncestralToken; 516 } 517 518 public void setAncestralToken(long ancestralToken) { 519 mAncestralToken = ancestralToken; 520 } 521 522 public long getCurrentToken() { 523 return mCurrentToken; 524 } 525 526 public void setCurrentToken(long currentToken) { 527 mCurrentToken = currentToken; 528 } 529 530 public ArraySet<String> getPendingInits() { 531 return mPendingInits; 532 } 533 534 public void clearPendingInits() { 535 mPendingInits.clear(); 536 } 537 538 public PerformFullTransportBackupTask getRunningFullBackupTask() { 539 return mRunningFullBackupTask; 540 } 541 542 public void setRunningFullBackupTask( 543 PerformFullTransportBackupTask runningFullBackupTask) { 544 mRunningFullBackupTask = runningFullBackupTask; 545 } 546 547 public static final class Lifecycle extends SystemService { 548 549 public Lifecycle(Context context) { 550 super(context); 551 sInstance = new Trampoline(context); 552 } 553 554 @Override 555 public void onStart() { 556 publishBinderService(Context.BACKUP_SERVICE, sInstance); 557 } 558 559 @Override 560 public void onUnlockUser(int userId) { 561 if (userId == UserHandle.USER_SYSTEM) { 562 sInstance.unlockSystemUser(); 563 } 564 } 565 } 566 567 // Called through the trampoline from onUnlockUser(), then we buck the work 568 // off to the background thread to keep the unlock time down. 569 public void unlockSystemUser() { 570 // Migrate legacy setting 571 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup migrate"); 572 if (!backupSettingMigrated(UserHandle.USER_SYSTEM)) { 573 if (DEBUG) { 574 Slog.i(TAG, "Backup enable apparently not migrated"); 575 } 576 final ContentResolver r = sInstance.mContext.getContentResolver(); 577 final int enableState = Settings.Secure.getIntForUser(r, 578 Settings.Secure.BACKUP_ENABLED, -1, UserHandle.USER_SYSTEM); 579 if (enableState >= 0) { 580 if (DEBUG) { 581 Slog.i(TAG, "Migrating enable state " + (enableState != 0)); 582 } 583 writeBackupEnableState(enableState != 0, UserHandle.USER_SYSTEM); 584 Settings.Secure.putStringForUser(r, 585 Settings.Secure.BACKUP_ENABLED, null, UserHandle.USER_SYSTEM); 586 } else { 587 if (DEBUG) { 588 Slog.i(TAG, "Backup not yet configured; retaining null enable state"); 589 } 590 } 591 } 592 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 593 594 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup enable"); 595 try { 596 sInstance.setBackupEnabled(readBackupEnableState(UserHandle.USER_SYSTEM)); 597 } catch (RemoteException e) { 598 // can't happen; it's a local object 599 } 600 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 601 } 602 603 // Bookkeeping of in-flight operations for timeout etc. purposes. The operation 604 // token is the index of the entry in the pending-operations list. 605 public static final int OP_PENDING = 0; 606 private static final int OP_ACKNOWLEDGED = 1; 607 private static final int OP_TIMEOUT = -1; 608 609 // Waiting for backup agent to respond during backup operation. 610 public static final int OP_TYPE_BACKUP_WAIT = 0; 611 612 // Waiting for backup agent to respond during restore operation. 613 public static final int OP_TYPE_RESTORE_WAIT = 1; 614 615 // An entire backup operation spanning multiple packages. 616 public static final int OP_TYPE_BACKUP = 2; 617 618 /** 619 * mCurrentOperations contains the list of currently active operations. 620 * 621 * If type of operation is OP_TYPE_WAIT, it are waiting for an ack or timeout. 622 * An operation wraps a BackupRestoreTask within it. 623 * It's the responsibility of this task to remove the operation from this array. 624 * 625 * A BackupRestore task gets notified of ack/timeout for the operation via 626 * BackupRestoreTask#handleCancel, BackupRestoreTask#operationComplete and notifyAll called 627 * on the mCurrentOpLock. 628 * {@link BackupManagerService#waitUntilOperationComplete(int)} is 629 * used in various places to 'wait' for notifyAll and detect change of pending state of an 630 * operation. So typically, an operation will be removed from this array by: 631 * - BackupRestoreTask#handleCancel and 632 * - BackupRestoreTask#operationComplete OR waitUntilOperationComplete. Do not remove at both 633 * these places because waitUntilOperationComplete relies on the operation being present to 634 * determine its completion status. 635 * 636 * If type of operation is OP_BACKUP, it is a task running backups. It provides a handle to 637 * cancel backup tasks. 638 */ 639 @GuardedBy("mCurrentOpLock") 640 private final SparseArray<Operation> mCurrentOperations = new SparseArray<>(); 641 private final Object mCurrentOpLock = new Object(); 642 private final Random mTokenGenerator = new Random(); 643 final AtomicInteger mNextToken = new AtomicInteger(); 644 645 private final SparseArray<AdbParams> mAdbBackupRestoreConfirmations = new SparseArray<>(); 646 647 // Where we keep our journal files and other bookkeeping 648 private File mBaseStateDir; 649 private File mDataDir; 650 private File mJournalDir; 651 @Nullable 652 private DataChangedJournal mJournal; 653 654 private final SecureRandom mRng = new SecureRandom(); 655 656 // Keep a log of all the apps we've ever backed up, and what the dataset tokens are for both 657 // the current backup dataset and the ancestral dataset. 658 private ProcessedPackagesJournal mProcessedPackagesJournal; 659 660 private static final int CURRENT_ANCESTRAL_RECORD_VERSION = 1; 661 // increment when the schema changes 662 private File mTokenFile; 663 private Set<String> mAncestralPackages = null; 664 private long mAncestralToken = 0; 665 private long mCurrentToken = 0; 666 667 // Persistently track the need to do a full init 668 private static final String INIT_SENTINEL_FILE_NAME = "_need_init_"; 669 private final ArraySet<String> mPendingInits = new ArraySet<>(); // transport names 670 671 // Round-robin queue for scheduling full backup passes 672 private static final int SCHEDULE_FILE_VERSION = 1; // current version of the schedule file 673 674 private File mFullBackupScheduleFile; 675 // If we're running a schedule-driven full backup, this is the task instance doing it 676 677 @GuardedBy("mQueueLock") 678 private PerformFullTransportBackupTask mRunningFullBackupTask; 679 680 @GuardedBy("mQueueLock") 681 private ArrayList<FullBackupEntry> mFullBackupQueue; 682 683 private BackupPolicyEnforcer mBackupPolicyEnforcer; 684 685 // Utility: build a new random integer token. The low bits are the ordinal of the 686 // operation for near-time uniqueness, and the upper bits are random for app- 687 // side unpredictability. 688 @Override 689 public int generateRandomIntegerToken() { 690 int token = mTokenGenerator.nextInt(); 691 if (token < 0) token = -token; 692 token &= ~0xFF; 693 token |= (mNextToken.incrementAndGet() & 0xFF); 694 return token; 695 } 696 697 /* 698 * Construct a backup agent instance for the metadata pseudopackage. This is a 699 * process-local non-lifecycle agent instance, so we manually set up the context 700 * topology for it. 701 */ 702 public PackageManagerBackupAgent makeMetadataAgent() { 703 PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(mPackageManager); 704 pmAgent.attach(mContext); 705 pmAgent.onCreate(); 706 return pmAgent; 707 } 708 709 /* 710 * Same as above but with the explicit package-set configuration. 711 */ 712 public PackageManagerBackupAgent makeMetadataAgent(List<PackageInfo> packages) { 713 PackageManagerBackupAgent pmAgent = 714 new PackageManagerBackupAgent(mPackageManager, packages); 715 pmAgent.attach(mContext); 716 pmAgent.onCreate(); 717 return pmAgent; 718 } 719 720 // ----- Debug-only backup operation trace ----- 721 public void addBackupTrace(String s) { 722 if (DEBUG_BACKUP_TRACE) { 723 synchronized (mBackupTrace) { 724 mBackupTrace.add(s); 725 } 726 } 727 } 728 729 public void clearBackupTrace() { 730 if (DEBUG_BACKUP_TRACE) { 731 synchronized (mBackupTrace) { 732 mBackupTrace.clear(); 733 } 734 } 735 } 736 737 // ----- Main service implementation ----- 738 739 public static BackupManagerService create( 740 Context context, 741 Trampoline parent, 742 HandlerThread backupThread) { 743 // Set up our transport options and initialize the default transport 744 SystemConfig systemConfig = SystemConfig.getInstance(); 745 Set<ComponentName> transportWhitelist = systemConfig.getBackupTransportWhitelist(); 746 if (transportWhitelist == null) { 747 transportWhitelist = Collections.emptySet(); 748 } 749 750 String transport = 751 Settings.Secure.getString( 752 context.getContentResolver(), Settings.Secure.BACKUP_TRANSPORT); 753 if (TextUtils.isEmpty(transport)) { 754 transport = null; 755 } 756 if (DEBUG) { 757 Slog.v(TAG, "Starting with transport " + transport); 758 } 759 TransportManager transportManager = 760 new TransportManager( 761 context, 762 transportWhitelist, 763 transport); 764 765 // If encrypted file systems is enabled or disabled, this call will return the 766 // correct directory. 767 File baseStateDir = new File(Environment.getDataDirectory(), "backup"); 768 769 // This dir on /cache is managed directly in init.rc 770 File dataDir = new File(Environment.getDownloadCacheDirectory(), "backup_stage"); 771 772 return new BackupManagerService( 773 context, 774 parent, 775 backupThread, 776 baseStateDir, 777 dataDir, 778 transportManager); 779 } 780 781 @VisibleForTesting 782 BackupManagerService( 783 Context context, 784 Trampoline parent, 785 HandlerThread backupThread, 786 File baseStateDir, 787 File dataDir, 788 TransportManager transportManager) { 789 mContext = context; 790 mPackageManager = context.getPackageManager(); 791 mPackageManagerBinder = AppGlobals.getPackageManager(); 792 mActivityManager = ActivityManager.getService(); 793 794 mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 795 mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); 796 mStorageManager = IStorageManager.Stub.asInterface(ServiceManager.getService("mount")); 797 798 mBackupManagerBinder = Trampoline.asInterface(parent.asBinder()); 799 800 mAgentTimeoutParameters = new 801 BackupAgentTimeoutParameters(Handler.getMain(), mContext.getContentResolver()); 802 mAgentTimeoutParameters.start(); 803 804 // spin up the backup/restore handler thread 805 mBackupHandler = new BackupHandler(this, backupThread.getLooper()); 806 807 // Set up our bookkeeping 808 final ContentResolver resolver = context.getContentResolver(); 809 mProvisioned = Settings.Global.getInt(resolver, 810 Settings.Global.DEVICE_PROVISIONED, 0) != 0; 811 mAutoRestore = Settings.Secure.getInt(resolver, 812 Settings.Secure.BACKUP_AUTO_RESTORE, 1) != 0; 813 814 mProvisionedObserver = new ProvisionedObserver(this, mBackupHandler); 815 resolver.registerContentObserver( 816 Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), 817 false, mProvisionedObserver); 818 819 mBaseStateDir = baseStateDir; 820 mBaseStateDir.mkdirs(); 821 if (!SELinux.restorecon(mBaseStateDir)) { 822 Slog.e(TAG, "SELinux restorecon failed on " + mBaseStateDir); 823 } 824 825 mDataDir = dataDir; 826 827 mBackupPasswordManager = new BackupPasswordManager(mContext, mBaseStateDir, mRng); 828 829 // Alarm receivers for scheduled backups & initialization operations 830 mRunBackupReceiver = new RunBackupReceiver(this); 831 IntentFilter filter = new IntentFilter(); 832 filter.addAction(RUN_BACKUP_ACTION); 833 context.registerReceiver(mRunBackupReceiver, filter, 834 android.Manifest.permission.BACKUP, null); 835 836 mRunInitReceiver = new RunInitializeReceiver(this); 837 filter = new IntentFilter(); 838 filter.addAction(RUN_INITIALIZE_ACTION); 839 context.registerReceiver(mRunInitReceiver, filter, 840 android.Manifest.permission.BACKUP, null); 841 842 Intent backupIntent = new Intent(RUN_BACKUP_ACTION); 843 backupIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 844 mRunBackupIntent = PendingIntent.getBroadcast(context, 0, backupIntent, 0); 845 846 Intent initIntent = new Intent(RUN_INITIALIZE_ACTION); 847 initIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 848 mRunInitIntent = PendingIntent.getBroadcast(context, 0, initIntent, 0); 849 850 // Set up the backup-request journaling 851 mJournalDir = new File(mBaseStateDir, "pending"); 852 mJournalDir.mkdirs(); // creates mBaseStateDir along the way 853 mJournal = null; // will be created on first use 854 855 mConstants = new BackupManagerConstants(mBackupHandler, mContext.getContentResolver()); 856 // We are observing changes to the constants throughout the lifecycle of BMS. This is 857 // because we reference the constants in multiple areas of BMS, which otherwise would 858 // require frequent starting and stopping. 859 mConstants.start(); 860 861 // Set up the various sorts of package tracking we do 862 mFullBackupScheduleFile = new File(mBaseStateDir, "fb-schedule"); 863 initPackageTracking(); 864 865 // Build our mapping of uid to backup client services. This implicitly 866 // schedules a backup pass on the Package Manager metadata the first 867 // time anything needs to be backed up. 868 synchronized (mBackupParticipants) { 869 addPackageParticipantsLocked(null); 870 } 871 872 mTransportManager = transportManager; 873 mTransportManager.setOnTransportRegisteredListener(this::onTransportRegistered); 874 mRegisterTransportsRequestedTime = SystemClock.elapsedRealtime(); 875 mBackupHandler.postDelayed( 876 mTransportManager::registerTransports, INITIALIZATION_DELAY_MILLIS); 877 878 // Now that we know about valid backup participants, parse any leftover journal files into 879 // the pending backup set 880 mBackupHandler.postDelayed(this::parseLeftoverJournals, INITIALIZATION_DELAY_MILLIS); 881 882 // Power management 883 mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*"); 884 885 mBackupPolicyEnforcer = new BackupPolicyEnforcer(context); 886 } 887 888 private void initPackageTracking() { 889 if (MORE_DEBUG) Slog.v(TAG, "` tracking"); 890 891 // Remember our ancestral dataset 892 mTokenFile = new File(mBaseStateDir, "ancestral"); 893 try (DataInputStream tokenStream = new DataInputStream(new BufferedInputStream( 894 new FileInputStream(mTokenFile)))) { 895 int version = tokenStream.readInt(); 896 if (version == CURRENT_ANCESTRAL_RECORD_VERSION) { 897 mAncestralToken = tokenStream.readLong(); 898 mCurrentToken = tokenStream.readLong(); 899 900 int numPackages = tokenStream.readInt(); 901 if (numPackages >= 0) { 902 mAncestralPackages = new HashSet<>(); 903 for (int i = 0; i < numPackages; i++) { 904 String pkgName = tokenStream.readUTF(); 905 mAncestralPackages.add(pkgName); 906 } 907 } 908 } 909 } catch (FileNotFoundException fnf) { 910 // Probably innocuous 911 Slog.v(TAG, "No ancestral data"); 912 } catch (IOException e) { 913 Slog.w(TAG, "Unable to read token file", e); 914 } 915 916 mProcessedPackagesJournal = new ProcessedPackagesJournal(mBaseStateDir); 917 mProcessedPackagesJournal.init(); 918 919 synchronized (mQueueLock) { 920 // Resume the full-data backup queue 921 mFullBackupQueue = readFullBackupSchedule(); 922 } 923 924 // Register for broadcasts about package install, etc., so we can 925 // update the provider list. 926 IntentFilter filter = new IntentFilter(); 927 filter.addAction(Intent.ACTION_PACKAGE_ADDED); 928 filter.addAction(Intent.ACTION_PACKAGE_REMOVED); 929 filter.addAction(Intent.ACTION_PACKAGE_CHANGED); 930 filter.addDataScheme("package"); 931 mContext.registerReceiver(mBroadcastReceiver, filter); 932 // Register for events related to sdcard installation. 933 IntentFilter sdFilter = new IntentFilter(); 934 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); 935 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); 936 mContext.registerReceiver(mBroadcastReceiver, sdFilter); 937 } 938 939 private ArrayList<FullBackupEntry> readFullBackupSchedule() { 940 boolean changed = false; 941 ArrayList<FullBackupEntry> schedule = null; 942 List<PackageInfo> apps = 943 PackageManagerBackupAgent.getStorableApplications(mPackageManager); 944 945 if (mFullBackupScheduleFile.exists()) { 946 try (FileInputStream fstream = new FileInputStream(mFullBackupScheduleFile); 947 BufferedInputStream bufStream = new BufferedInputStream(fstream); 948 DataInputStream in = new DataInputStream(bufStream)) { 949 int version = in.readInt(); 950 if (version != SCHEDULE_FILE_VERSION) { 951 Slog.e(TAG, "Unknown backup schedule version " + version); 952 return null; 953 } 954 955 final int N = in.readInt(); 956 schedule = new ArrayList<>(N); 957 958 // HashSet instead of ArraySet specifically because we want the eventual 959 // lookups against O(hundreds) of entries to be as fast as possible, and 960 // we discard the set immediately after the scan so the extra memory 961 // overhead is transient. 962 HashSet<String> foundApps = new HashSet<>(N); 963 964 for (int i = 0; i < N; i++) { 965 String pkgName = in.readUTF(); 966 long lastBackup = in.readLong(); 967 foundApps.add(pkgName); // all apps that we've addressed already 968 try { 969 PackageInfo pkg = mPackageManager.getPackageInfo(pkgName, 0); 970 if (AppBackupUtils.appGetsFullBackup(pkg) 971 && AppBackupUtils.appIsEligibleForBackup( 972 pkg.applicationInfo, mPackageManager)) { 973 schedule.add(new FullBackupEntry(pkgName, lastBackup)); 974 } else { 975 if (DEBUG) { 976 Slog.i(TAG, "Package " + pkgName 977 + " no longer eligible for full backup"); 978 } 979 } 980 } catch (NameNotFoundException e) { 981 if (DEBUG) { 982 Slog.i(TAG, "Package " + pkgName 983 + " not installed; dropping from full backup"); 984 } 985 } 986 } 987 988 // New apps can arrive "out of band" via OTA and similar, so we also need to 989 // scan to make sure that we're tracking all full-backup candidates properly 990 for (PackageInfo app : apps) { 991 if (AppBackupUtils.appGetsFullBackup(app) 992 && AppBackupUtils.appIsEligibleForBackup( 993 app.applicationInfo, mPackageManager)) { 994 if (!foundApps.contains(app.packageName)) { 995 if (MORE_DEBUG) { 996 Slog.i(TAG, "New full backup app " + app.packageName + " found"); 997 } 998 schedule.add(new FullBackupEntry(app.packageName, 0)); 999 changed = true; 1000 } 1001 } 1002 } 1003 1004 Collections.sort(schedule); 1005 } catch (Exception e) { 1006 Slog.e(TAG, "Unable to read backup schedule", e); 1007 mFullBackupScheduleFile.delete(); 1008 schedule = null; 1009 } 1010 } 1011 1012 if (schedule == null) { 1013 // no prior queue record, or unable to read it. Set up the queue 1014 // from scratch. 1015 changed = true; 1016 schedule = new ArrayList<>(apps.size()); 1017 for (PackageInfo info : apps) { 1018 if (AppBackupUtils.appGetsFullBackup(info) && AppBackupUtils.appIsEligibleForBackup( 1019 info.applicationInfo, mPackageManager)) { 1020 schedule.add(new FullBackupEntry(info.packageName, 0)); 1021 } 1022 } 1023 } 1024 1025 if (changed) { 1026 writeFullBackupScheduleAsync(); 1027 } 1028 return schedule; 1029 } 1030 1031 private Runnable mFullBackupScheduleWriter = new Runnable() { 1032 @Override 1033 public void run() { 1034 synchronized (mQueueLock) { 1035 try { 1036 ByteArrayOutputStream bufStream = new ByteArrayOutputStream(4096); 1037 DataOutputStream bufOut = new DataOutputStream(bufStream); 1038 bufOut.writeInt(SCHEDULE_FILE_VERSION); 1039 1040 // version 1: 1041 // 1042 // [int] # of packages in the queue = N 1043 // N * { 1044 // [utf8] package name 1045 // [long] last backup time for this package 1046 // } 1047 int N = mFullBackupQueue.size(); 1048 bufOut.writeInt(N); 1049 1050 for (int i = 0; i < N; i++) { 1051 FullBackupEntry entry = mFullBackupQueue.get(i); 1052 bufOut.writeUTF(entry.packageName); 1053 bufOut.writeLong(entry.lastBackup); 1054 } 1055 bufOut.flush(); 1056 1057 AtomicFile af = new AtomicFile(mFullBackupScheduleFile); 1058 FileOutputStream out = af.startWrite(); 1059 out.write(bufStream.toByteArray()); 1060 af.finishWrite(out); 1061 } catch (Exception e) { 1062 Slog.e(TAG, "Unable to write backup schedule!", e); 1063 } 1064 } 1065 } 1066 }; 1067 1068 private void writeFullBackupScheduleAsync() { 1069 mBackupHandler.removeCallbacks(mFullBackupScheduleWriter); 1070 mBackupHandler.post(mFullBackupScheduleWriter); 1071 } 1072 1073 private void parseLeftoverJournals() { 1074 ArrayList<DataChangedJournal> journals = DataChangedJournal.listJournals(mJournalDir); 1075 for (DataChangedJournal journal : journals) { 1076 if (!journal.equals(mJournal)) { 1077 try { 1078 journal.forEach(packageName -> { 1079 Slog.i(TAG, "Found stale backup journal, scheduling"); 1080 if (MORE_DEBUG) Slog.i(TAG, " " + packageName); 1081 dataChangedImpl(packageName); 1082 }); 1083 } catch (IOException e) { 1084 Slog.e(TAG, "Can't read " + journal, e); 1085 } 1086 } 1087 } 1088 } 1089 1090 // Used for generating random salts or passwords 1091 public byte[] randomBytes(int bits) { 1092 byte[] array = new byte[bits / 8]; 1093 mRng.nextBytes(array); 1094 return array; 1095 } 1096 1097 @Override 1098 public boolean setBackupPassword(String currentPw, String newPw) { 1099 return mBackupPasswordManager.setBackupPassword(currentPw, newPw); 1100 } 1101 1102 @Override 1103 public boolean hasBackupPassword() { 1104 return mBackupPasswordManager.hasBackupPassword(); 1105 } 1106 1107 public boolean backupPasswordMatches(String currentPw) { 1108 return mBackupPasswordManager.backupPasswordMatches(currentPw); 1109 } 1110 1111 /** 1112 * Maintain persistent state around whether need to do an initialize operation. This will lock 1113 * on {@link #getQueueLock()}. 1114 */ 1115 public void recordInitPending( 1116 boolean isPending, String transportName, String transportDirName) { 1117 synchronized (mQueueLock) { 1118 if (MORE_DEBUG) { 1119 Slog.i(TAG, "recordInitPending(" + isPending + ") on transport " + transportName); 1120 } 1121 1122 File stateDir = new File(mBaseStateDir, transportDirName); 1123 File initPendingFile = new File(stateDir, INIT_SENTINEL_FILE_NAME); 1124 1125 if (isPending) { 1126 // We need an init before we can proceed with sending backup data. 1127 // Record that with an entry in our set of pending inits, as well as 1128 // journaling it via creation of a sentinel file. 1129 mPendingInits.add(transportName); 1130 try { 1131 (new FileOutputStream(initPendingFile)).close(); 1132 } catch (IOException ioe) { 1133 // Something is badly wrong with our permissions; just try to move on 1134 } 1135 } else { 1136 // No more initialization needed; wipe the journal and reset our state. 1137 initPendingFile.delete(); 1138 mPendingInits.remove(transportName); 1139 } 1140 } 1141 } 1142 1143 // Reset all of our bookkeeping, in response to having been told that 1144 // the backend data has been wiped [due to idle expiry, for example], 1145 // so we must re-upload all saved settings. 1146 public void resetBackupState(File stateFileDir) { 1147 synchronized (mQueueLock) { 1148 mProcessedPackagesJournal.reset(); 1149 1150 mCurrentToken = 0; 1151 writeRestoreTokens(); 1152 1153 // Remove all the state files 1154 for (File sf : stateFileDir.listFiles()) { 1155 // ... but don't touch the needs-init sentinel 1156 if (!sf.getName().equals(INIT_SENTINEL_FILE_NAME)) { 1157 sf.delete(); 1158 } 1159 } 1160 } 1161 1162 // Enqueue a new backup of every participant 1163 synchronized (mBackupParticipants) { 1164 final int N = mBackupParticipants.size(); 1165 for (int i = 0; i < N; i++) { 1166 HashSet<String> participants = mBackupParticipants.valueAt(i); 1167 if (participants != null) { 1168 for (String packageName : participants) { 1169 dataChangedImpl(packageName); 1170 } 1171 } 1172 } 1173 } 1174 } 1175 1176 private void onTransportRegistered(String transportName, String transportDirName) { 1177 if (DEBUG) { 1178 long timeMs = SystemClock.elapsedRealtime() - mRegisterTransportsRequestedTime; 1179 Slog.d(TAG, "Transport " + transportName + " registered " + timeMs 1180 + "ms after first request (delay = " + INITIALIZATION_DELAY_MILLIS + "ms)"); 1181 } 1182 1183 File stateDir = new File(mBaseStateDir, transportDirName); 1184 stateDir.mkdirs(); 1185 1186 File initSentinel = new File(stateDir, INIT_SENTINEL_FILE_NAME); 1187 if (initSentinel.exists()) { 1188 synchronized (mQueueLock) { 1189 mPendingInits.add(transportName); 1190 1191 // TODO: pick a better starting time than now + 1 minute 1192 long delay = 1000 * 60; // one minute, in milliseconds 1193 mAlarmManager.set(AlarmManager.RTC_WAKEUP, 1194 System.currentTimeMillis() + delay, mRunInitIntent); 1195 } 1196 } 1197 } 1198 1199 // ----- Track installation/removal of packages ----- 1200 private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 1201 public void onReceive(Context context, Intent intent) { 1202 if (MORE_DEBUG) Slog.d(TAG, "Received broadcast " + intent); 1203 1204 String action = intent.getAction(); 1205 boolean replacing = false; 1206 boolean added = false; 1207 boolean changed = false; 1208 Bundle extras = intent.getExtras(); 1209 String pkgList[] = null; 1210 if (Intent.ACTION_PACKAGE_ADDED.equals(action) || 1211 Intent.ACTION_PACKAGE_REMOVED.equals(action) || 1212 Intent.ACTION_PACKAGE_CHANGED.equals(action)) { 1213 Uri uri = intent.getData(); 1214 if (uri == null) { 1215 return; 1216 } 1217 final String pkgName = uri.getSchemeSpecificPart(); 1218 if (pkgName != null) { 1219 pkgList = new String[]{pkgName}; 1220 } 1221 changed = Intent.ACTION_PACKAGE_CHANGED.equals(action); 1222 1223 // At package-changed we only care about looking at new transport states 1224 if (changed) { 1225 final String[] components = 1226 intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST); 1227 1228 if (MORE_DEBUG) { 1229 Slog.i(TAG, "Package " + pkgName + " changed; rechecking"); 1230 for (int i = 0; i < components.length; i++) { 1231 Slog.i(TAG, " * " + components[i]); 1232 } 1233 } 1234 1235 mBackupHandler.post( 1236 () -> mTransportManager.onPackageChanged(pkgName, components)); 1237 return; // nothing more to do in the PACKAGE_CHANGED case 1238 } 1239 1240 added = Intent.ACTION_PACKAGE_ADDED.equals(action); 1241 replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false); 1242 } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) { 1243 added = true; 1244 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 1245 } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { 1246 added = false; 1247 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 1248 } 1249 1250 if (pkgList == null || pkgList.length == 0) { 1251 return; 1252 } 1253 1254 final int uid = extras.getInt(Intent.EXTRA_UID); 1255 if (added) { 1256 synchronized (mBackupParticipants) { 1257 if (replacing) { 1258 // This is the package-replaced case; we just remove the entry 1259 // under the old uid and fall through to re-add. If an app 1260 // just added key/value backup participation, this picks it up 1261 // as a known participant. 1262 removePackageParticipantsLocked(pkgList, uid); 1263 } 1264 addPackageParticipantsLocked(pkgList); 1265 } 1266 // If they're full-backup candidates, add them there instead 1267 final long now = System.currentTimeMillis(); 1268 for (final String packageName : pkgList) { 1269 try { 1270 PackageInfo app = mPackageManager.getPackageInfo(packageName, 0); 1271 if (AppBackupUtils.appGetsFullBackup(app) 1272 && AppBackupUtils.appIsEligibleForBackup( 1273 app.applicationInfo, mPackageManager)) { 1274 enqueueFullBackup(packageName, now); 1275 scheduleNextFullBackupJob(0); 1276 } else { 1277 // The app might have just transitioned out of full-data into 1278 // doing key/value backups, or might have just disabled backups 1279 // entirely. Make sure it is no longer in the full-data queue. 1280 synchronized (mQueueLock) { 1281 dequeueFullBackupLocked(packageName); 1282 } 1283 writeFullBackupScheduleAsync(); 1284 } 1285 1286 mBackupHandler.post( 1287 () -> mTransportManager.onPackageAdded(packageName)); 1288 1289 } catch (NameNotFoundException e) { 1290 // doesn't really exist; ignore it 1291 if (DEBUG) { 1292 Slog.w(TAG, "Can't resolve new app " + packageName); 1293 } 1294 } 1295 } 1296 1297 // Whenever a package is added or updated we need to update 1298 // the package metadata bookkeeping. 1299 dataChangedImpl(PACKAGE_MANAGER_SENTINEL); 1300 } else { 1301 if (replacing) { 1302 // The package is being updated. We'll receive a PACKAGE_ADDED shortly. 1303 } else { 1304 // Outright removal. In the full-data case, the app will be dropped 1305 // from the queue when its (now obsolete) name comes up again for 1306 // backup. 1307 synchronized (mBackupParticipants) { 1308 removePackageParticipantsLocked(pkgList, uid); 1309 } 1310 } 1311 for (final String pkgName : pkgList) { 1312 mBackupHandler.post( 1313 () -> mTransportManager.onPackageRemoved(pkgName)); 1314 } 1315 } 1316 } 1317 }; 1318 1319 // Add the backup agents in the given packages to our set of known backup participants. 1320 // If 'packageNames' is null, adds all backup agents in the whole system. 1321 private void addPackageParticipantsLocked(String[] packageNames) { 1322 // Look for apps that define the android:backupAgent attribute 1323 List<PackageInfo> targetApps = allAgentPackages(); 1324 if (packageNames != null) { 1325 if (MORE_DEBUG) Slog.v(TAG, "addPackageParticipantsLocked: #" + packageNames.length); 1326 for (String packageName : packageNames) { 1327 addPackageParticipantsLockedInner(packageName, targetApps); 1328 } 1329 } else { 1330 if (MORE_DEBUG) Slog.v(TAG, "addPackageParticipantsLocked: all"); 1331 addPackageParticipantsLockedInner(null, targetApps); 1332 } 1333 } 1334 1335 private void addPackageParticipantsLockedInner(String packageName, 1336 List<PackageInfo> targetPkgs) { 1337 if (MORE_DEBUG) { 1338 Slog.v(TAG, "Examining " + packageName + " for backup agent"); 1339 } 1340 1341 for (PackageInfo pkg : targetPkgs) { 1342 if (packageName == null || pkg.packageName.equals(packageName)) { 1343 int uid = pkg.applicationInfo.uid; 1344 HashSet<String> set = mBackupParticipants.get(uid); 1345 if (set == null) { 1346 set = new HashSet<>(); 1347 mBackupParticipants.put(uid, set); 1348 } 1349 set.add(pkg.packageName); 1350 if (MORE_DEBUG) Slog.v(TAG, "Agent found; added"); 1351 1352 // Schedule a backup for it on general principles 1353 if (MORE_DEBUG) Slog.i(TAG, "Scheduling backup for new app " + pkg.packageName); 1354 Message msg = mBackupHandler 1355 .obtainMessage(MSG_SCHEDULE_BACKUP_PACKAGE, pkg.packageName); 1356 mBackupHandler.sendMessage(msg); 1357 } 1358 } 1359 } 1360 1361 // Remove the given packages' entries from our known active set. 1362 private void removePackageParticipantsLocked(String[] packageNames, int oldUid) { 1363 if (packageNames == null) { 1364 Slog.w(TAG, "removePackageParticipants with null list"); 1365 return; 1366 } 1367 1368 if (MORE_DEBUG) { 1369 Slog.v(TAG, "removePackageParticipantsLocked: uid=" + oldUid 1370 + " #" + packageNames.length); 1371 } 1372 for (String pkg : packageNames) { 1373 // Known previous UID, so we know which package set to check 1374 HashSet<String> set = mBackupParticipants.get(oldUid); 1375 if (set != null && set.contains(pkg)) { 1376 removePackageFromSetLocked(set, pkg); 1377 if (set.isEmpty()) { 1378 if (MORE_DEBUG) Slog.v(TAG, " last one of this uid; purging set"); 1379 mBackupParticipants.remove(oldUid); 1380 } 1381 } 1382 } 1383 } 1384 1385 private void removePackageFromSetLocked(final HashSet<String> set, 1386 final String packageName) { 1387 if (set.contains(packageName)) { 1388 // Found it. Remove this one package from the bookkeeping, and 1389 // if it's the last participating app under this uid we drop the 1390 // (now-empty) set as well. 1391 // Note that we deliberately leave it 'known' in the "ever backed up" 1392 // bookkeeping so that its current-dataset data will be retrieved 1393 // if the app is subsequently reinstalled 1394 if (MORE_DEBUG) Slog.v(TAG, " removing participant " + packageName); 1395 set.remove(packageName); 1396 mPendingBackups.remove(packageName); 1397 } 1398 } 1399 1400 // Returns the set of all applications that define an android:backupAgent attribute 1401 private List<PackageInfo> allAgentPackages() { 1402 // !!! TODO: cache this and regenerate only when necessary 1403 int flags = PackageManager.GET_SIGNING_CERTIFICATES; 1404 List<PackageInfo> packages = mPackageManager.getInstalledPackages(flags); 1405 int N = packages.size(); 1406 for (int a = N - 1; a >= 0; a--) { 1407 PackageInfo pkg = packages.get(a); 1408 try { 1409 ApplicationInfo app = pkg.applicationInfo; 1410 if (((app.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) 1411 || app.backupAgentName == null 1412 || (app.flags & ApplicationInfo.FLAG_FULL_BACKUP_ONLY) != 0) { 1413 packages.remove(a); 1414 } else { 1415 // we will need the shared library path, so look that up and store it here. 1416 // This is used implicitly when we pass the PackageInfo object off to 1417 // the Activity Manager to launch the app for backup/restore purposes. 1418 app = mPackageManager.getApplicationInfo(pkg.packageName, 1419 PackageManager.GET_SHARED_LIBRARY_FILES); 1420 pkg.applicationInfo.sharedLibraryFiles = app.sharedLibraryFiles; 1421 } 1422 } catch (NameNotFoundException e) { 1423 packages.remove(a); 1424 } 1425 } 1426 return packages; 1427 } 1428 1429 // Called from the backup tasks: record that the given app has been successfully 1430 // backed up at least once. This includes both key/value and full-data backups 1431 // through the transport. 1432 public void logBackupComplete(String packageName) { 1433 if (packageName.equals(PACKAGE_MANAGER_SENTINEL)) return; 1434 1435 for (String receiver : mConstants.getBackupFinishedNotificationReceivers()) { 1436 final Intent notification = new Intent(); 1437 notification.setAction(BACKUP_FINISHED_ACTION); 1438 notification.setPackage(receiver); 1439 notification.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES | 1440 Intent.FLAG_RECEIVER_FOREGROUND); 1441 notification.putExtra(BACKUP_FINISHED_PACKAGE_EXTRA, packageName); 1442 mContext.sendBroadcastAsUser(notification, UserHandle.OWNER); 1443 } 1444 1445 mProcessedPackagesJournal.addPackage(packageName); 1446 } 1447 1448 // Persistently record the current and ancestral backup tokens as well 1449 // as the set of packages with data [supposedly] available in the 1450 // ancestral dataset. 1451 public void writeRestoreTokens() { 1452 try (RandomAccessFile af = new RandomAccessFile(mTokenFile, "rwd")) { 1453 // First, the version number of this record, for futureproofing 1454 af.writeInt(CURRENT_ANCESTRAL_RECORD_VERSION); 1455 1456 // Write the ancestral and current tokens 1457 af.writeLong(mAncestralToken); 1458 af.writeLong(mCurrentToken); 1459 1460 // Now write the set of ancestral packages 1461 if (mAncestralPackages == null) { 1462 af.writeInt(-1); 1463 } else { 1464 af.writeInt(mAncestralPackages.size()); 1465 if (DEBUG) Slog.v(TAG, "Ancestral packages: " + mAncestralPackages.size()); 1466 for (String pkgName : mAncestralPackages) { 1467 af.writeUTF(pkgName); 1468 if (MORE_DEBUG) Slog.v(TAG, " " + pkgName); 1469 } 1470 } 1471 } catch (IOException e) { 1472 Slog.w(TAG, "Unable to write token file:", e); 1473 } 1474 } 1475 1476 // fire off a backup agent, blocking until it attaches or times out 1477 @Override 1478 public IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode) { 1479 IBackupAgent agent = null; 1480 synchronized (mAgentConnectLock) { 1481 mConnecting = true; 1482 mConnectedAgent = null; 1483 try { 1484 if (mActivityManager.bindBackupAgent(app.packageName, mode, 1485 UserHandle.USER_OWNER)) { 1486 Slog.d(TAG, "awaiting agent for " + app); 1487 1488 // success; wait for the agent to arrive 1489 // only wait 10 seconds for the bind to happen 1490 long timeoutMark = System.currentTimeMillis() + TIMEOUT_INTERVAL; 1491 while (mConnecting && mConnectedAgent == null 1492 && (System.currentTimeMillis() < timeoutMark)) { 1493 try { 1494 mAgentConnectLock.wait(5000); 1495 } catch (InterruptedException e) { 1496 // just bail 1497 Slog.w(TAG, "Interrupted: " + e); 1498 mConnecting = false; 1499 mConnectedAgent = null; 1500 } 1501 } 1502 1503 // if we timed out with no connect, abort and move on 1504 if (mConnecting == true) { 1505 Slog.w(TAG, "Timeout waiting for agent " + app); 1506 mConnectedAgent = null; 1507 } 1508 if (DEBUG) Slog.i(TAG, "got agent " + mConnectedAgent); 1509 agent = mConnectedAgent; 1510 } 1511 } catch (RemoteException e) { 1512 // can't happen - ActivityManager is local 1513 } 1514 } 1515 if (agent == null) { 1516 try { 1517 mActivityManager.clearPendingBackup(); 1518 } catch (RemoteException e) { 1519 // can't happen - ActivityManager is local 1520 } 1521 } 1522 return agent; 1523 } 1524 1525 // clear an application's data, blocking until the operation completes or times out 1526 // if keepSystemState is true, we intentionally do not also clear system state that 1527 // would ordinarily also be cleared, because we aren't actually wiping the app back 1528 // to empty; we're bringing it into the actual expected state related to the already- 1529 // restored notification state etc. 1530 public void clearApplicationDataSynchronous(String packageName, boolean keepSystemState) { 1531 // Don't wipe packages marked allowClearUserData=false 1532 try { 1533 PackageInfo info = mPackageManager.getPackageInfo(packageName, 0); 1534 if ((info.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA) == 0) { 1535 if (MORE_DEBUG) { 1536 Slog.i(TAG, "allowClearUserData=false so not wiping " 1537 + packageName); 1538 } 1539 return; 1540 } 1541 } catch (NameNotFoundException e) { 1542 Slog.w(TAG, "Tried to clear data for " + packageName + " but not found"); 1543 return; 1544 } 1545 1546 ClearDataObserver observer = new ClearDataObserver(this); 1547 1548 synchronized (mClearDataLock) { 1549 mClearingData = true; 1550 try { 1551 mActivityManager.clearApplicationUserData(packageName, keepSystemState, observer, 0); 1552 } catch (RemoteException e) { 1553 // can't happen because the activity manager is in this process 1554 } 1555 1556 // only wait 10 seconds for the clear data to happen 1557 long timeoutMark = System.currentTimeMillis() + TIMEOUT_INTERVAL; 1558 while (mClearingData && (System.currentTimeMillis() < timeoutMark)) { 1559 try { 1560 mClearDataLock.wait(5000); 1561 } catch (InterruptedException e) { 1562 // won't happen, but still. 1563 mClearingData = false; 1564 } 1565 } 1566 } 1567 } 1568 1569 // Get the restore-set token for the best-available restore set for this package: 1570 // the active set if possible, else the ancestral one. Returns zero if none available. 1571 @Override 1572 public long getAvailableRestoreToken(String packageName) { 1573 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, 1574 "getAvailableRestoreToken"); 1575 1576 long token = mAncestralToken; 1577 synchronized (mQueueLock) { 1578 if (mCurrentToken != 0 && mProcessedPackagesJournal.hasBeenProcessed(packageName)) { 1579 if (MORE_DEBUG) { 1580 Slog.i(TAG, "App in ever-stored, so using current token"); 1581 } 1582 token = mCurrentToken; 1583 } 1584 } 1585 if (MORE_DEBUG) Slog.i(TAG, "getAvailableRestoreToken() == " + token); 1586 return token; 1587 } 1588 1589 @Override 1590 public int requestBackup(String[] packages, IBackupObserver observer, int flags) { 1591 return requestBackup(packages, observer, null, flags); 1592 } 1593 1594 @Override 1595 public int requestBackup(String[] packages, IBackupObserver observer, 1596 IBackupManagerMonitor monitor, int flags) { 1597 mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "requestBackup"); 1598 1599 if (packages == null || packages.length < 1) { 1600 Slog.e(TAG, "No packages named for backup request"); 1601 BackupObserverUtils.sendBackupFinished(observer, BackupManager.ERROR_TRANSPORT_ABORTED); 1602 monitor = BackupManagerMonitorUtils.monitorEvent(monitor, 1603 BackupManagerMonitor.LOG_EVENT_ID_NO_PACKAGES, 1604 null, BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT, null); 1605 throw new IllegalArgumentException("No packages are provided for backup"); 1606 } 1607 1608 if (!mEnabled || !mProvisioned) { 1609 Slog.i(TAG, "Backup requested but e=" + mEnabled + " p=" + mProvisioned); 1610 BackupObserverUtils.sendBackupFinished(observer, 1611 BackupManager.ERROR_BACKUP_NOT_ALLOWED); 1612 final int logTag = mProvisioned 1613 ? BackupManagerMonitor.LOG_EVENT_ID_BACKUP_DISABLED 1614 : BackupManagerMonitor.LOG_EVENT_ID_DEVICE_NOT_PROVISIONED; 1615 monitor = BackupManagerMonitorUtils.monitorEvent(monitor, logTag, null, 1616 BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, null); 1617 return BackupManager.ERROR_BACKUP_NOT_ALLOWED; 1618 } 1619 1620 final TransportClient transportClient; 1621 final String transportDirName; 1622 try { 1623 transportDirName = 1624 mTransportManager.getTransportDirName( 1625 mTransportManager.getCurrentTransportName()); 1626 transportClient = 1627 mTransportManager.getCurrentTransportClientOrThrow("BMS.requestBackup()"); 1628 } catch (TransportNotRegisteredException e) { 1629 BackupObserverUtils.sendBackupFinished(observer, BackupManager.ERROR_TRANSPORT_ABORTED); 1630 monitor = BackupManagerMonitorUtils.monitorEvent(monitor, 1631 BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_IS_NULL, 1632 null, BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT, null); 1633 return BackupManager.ERROR_TRANSPORT_ABORTED; 1634 } 1635 1636 OnTaskFinishedListener listener = 1637 caller -> mTransportManager.disposeOfTransportClient(transportClient, caller); 1638 1639 ArrayList<String> fullBackupList = new ArrayList<>(); 1640 ArrayList<String> kvBackupList = new ArrayList<>(); 1641 for (String packageName : packages) { 1642 if (PACKAGE_MANAGER_SENTINEL.equals(packageName)) { 1643 kvBackupList.add(packageName); 1644 continue; 1645 } 1646 try { 1647 PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, 1648 PackageManager.GET_SIGNING_CERTIFICATES); 1649 if (!AppBackupUtils.appIsEligibleForBackup(packageInfo.applicationInfo, 1650 mPackageManager)) { 1651 BackupObserverUtils.sendBackupOnPackageResult(observer, packageName, 1652 BackupManager.ERROR_BACKUP_NOT_ALLOWED); 1653 continue; 1654 } 1655 if (AppBackupUtils.appGetsFullBackup(packageInfo)) { 1656 fullBackupList.add(packageInfo.packageName); 1657 } else { 1658 kvBackupList.add(packageInfo.packageName); 1659 } 1660 } catch (NameNotFoundException e) { 1661 BackupObserverUtils.sendBackupOnPackageResult(observer, packageName, 1662 BackupManager.ERROR_PACKAGE_NOT_FOUND); 1663 } 1664 } 1665 EventLog.writeEvent(EventLogTags.BACKUP_REQUESTED, packages.length, kvBackupList.size(), 1666 fullBackupList.size()); 1667 if (MORE_DEBUG) { 1668 Slog.i(TAG, "Backup requested for " + packages.length + " packages, of them: " + 1669 fullBackupList.size() + " full backups, " + kvBackupList.size() 1670 + " k/v backups"); 1671 } 1672 1673 boolean nonIncrementalBackup = (flags & BackupManager.FLAG_NON_INCREMENTAL_BACKUP) != 0; 1674 1675 Message msg = mBackupHandler.obtainMessage(MSG_REQUEST_BACKUP); 1676 msg.obj = new BackupParams(transportClient, transportDirName, kvBackupList, fullBackupList, 1677 observer, monitor, listener, true, nonIncrementalBackup); 1678 mBackupHandler.sendMessage(msg); 1679 return BackupManager.SUCCESS; 1680 } 1681 1682 // Cancel all running backups. 1683 @Override 1684 public void cancelBackups() { 1685 mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "cancelBackups"); 1686 if (MORE_DEBUG) { 1687 Slog.i(TAG, "cancelBackups() called."); 1688 } 1689 final long oldToken = Binder.clearCallingIdentity(); 1690 try { 1691 List<Integer> operationsToCancel = new ArrayList<>(); 1692 synchronized (mCurrentOpLock) { 1693 for (int i = 0; i < mCurrentOperations.size(); i++) { 1694 Operation op = mCurrentOperations.valueAt(i); 1695 int token = mCurrentOperations.keyAt(i); 1696 if (op.type == OP_TYPE_BACKUP) { 1697 operationsToCancel.add(token); 1698 } 1699 } 1700 } 1701 for (Integer token : operationsToCancel) { 1702 handleCancel(token, true /* cancelAll */); 1703 } 1704 // We don't want the backup jobs to kick in any time soon. 1705 // Reschedules them to run in the distant future. 1706 KeyValueBackupJob.schedule(mContext, BUSY_BACKOFF_MIN_MILLIS, mConstants); 1707 FullBackupJob.schedule(mContext, 2 * BUSY_BACKOFF_MIN_MILLIS, mConstants); 1708 } finally { 1709 Binder.restoreCallingIdentity(oldToken); 1710 } 1711 } 1712 1713 @Override 1714 public void prepareOperationTimeout(int token, long interval, BackupRestoreTask callback, 1715 int operationType) { 1716 if (operationType != OP_TYPE_BACKUP_WAIT && operationType != OP_TYPE_RESTORE_WAIT) { 1717 Slog.wtf(TAG, "prepareOperationTimeout() doesn't support operation " + 1718 Integer.toHexString(token) + " of type " + operationType); 1719 return; 1720 } 1721 if (MORE_DEBUG) { 1722 Slog.v(TAG, "starting timeout: token=" + Integer.toHexString(token) 1723 + " interval=" + interval + " callback=" + callback); 1724 } 1725 1726 synchronized (mCurrentOpLock) { 1727 mCurrentOperations.put(token, new Operation(OP_PENDING, callback, operationType)); 1728 Message msg = mBackupHandler.obtainMessage(getMessageIdForOperationType(operationType), 1729 token, 0, callback); 1730 mBackupHandler.sendMessageDelayed(msg, interval); 1731 } 1732 } 1733 1734 private int getMessageIdForOperationType(int operationType) { 1735 switch (operationType) { 1736 case OP_TYPE_BACKUP_WAIT: 1737 return MSG_BACKUP_OPERATION_TIMEOUT; 1738 case OP_TYPE_RESTORE_WAIT: 1739 return MSG_RESTORE_OPERATION_TIMEOUT; 1740 default: 1741 Slog.wtf(TAG, "getMessageIdForOperationType called on invalid operation type: " + 1742 operationType); 1743 return -1; 1744 } 1745 } 1746 1747 public void removeOperation(int token) { 1748 if (MORE_DEBUG) { 1749 Slog.d(TAG, "Removing operation token=" + Integer.toHexString(token)); 1750 } 1751 synchronized (mCurrentOpLock) { 1752 if (mCurrentOperations.get(token) == null) { 1753 Slog.w(TAG, "Duplicate remove for operation. token=" + 1754 Integer.toHexString(token)); 1755 } 1756 mCurrentOperations.remove(token); 1757 } 1758 } 1759 1760 // synchronous waiter case 1761 @Override 1762 public boolean waitUntilOperationComplete(int token) { 1763 if (MORE_DEBUG) { 1764 Slog.i(TAG, "Blocking until operation complete for " 1765 + Integer.toHexString(token)); 1766 } 1767 int finalState = OP_PENDING; 1768 Operation op = null; 1769 synchronized (mCurrentOpLock) { 1770 while (true) { 1771 op = mCurrentOperations.get(token); 1772 if (op == null) { 1773 // mysterious disappearance: treat as success with no callback 1774 break; 1775 } else { 1776 if (op.state == OP_PENDING) { 1777 try { 1778 mCurrentOpLock.wait(); 1779 } catch (InterruptedException e) { 1780 } 1781 // When the wait is notified we loop around and recheck the current state 1782 } else { 1783 if (MORE_DEBUG) { 1784 Slog.d(TAG, "Unblocked waiting for operation token=" + 1785 Integer.toHexString(token)); 1786 } 1787 // No longer pending; we're done 1788 finalState = op.state; 1789 break; 1790 } 1791 } 1792 } 1793 } 1794 1795 removeOperation(token); 1796 if (op != null) { 1797 mBackupHandler.removeMessages(getMessageIdForOperationType(op.type)); 1798 } 1799 if (MORE_DEBUG) { 1800 Slog.v(TAG, "operation " + Integer.toHexString(token) 1801 + " complete: finalState=" + finalState); 1802 } 1803 return finalState == OP_ACKNOWLEDGED; 1804 } 1805 1806 public void handleCancel(int token, boolean cancelAll) { 1807 // Notify any synchronous waiters 1808 Operation op = null; 1809 synchronized (mCurrentOpLock) { 1810 op = mCurrentOperations.get(token); 1811 if (MORE_DEBUG) { 1812 if (op == null) { 1813 Slog.w(TAG, "Cancel of token " + Integer.toHexString(token) 1814 + " but no op found"); 1815 } 1816 } 1817 int state = (op != null) ? op.state : OP_TIMEOUT; 1818 if (state == OP_ACKNOWLEDGED) { 1819 // The operation finished cleanly, so we have nothing more to do. 1820 if (DEBUG) { 1821 Slog.w(TAG, "Operation already got an ack." + 1822 "Should have been removed from mCurrentOperations."); 1823 } 1824 op = null; 1825 mCurrentOperations.delete(token); 1826 } else if (state == OP_PENDING) { 1827 if (DEBUG) Slog.v(TAG, "Cancel: token=" + Integer.toHexString(token)); 1828 op.state = OP_TIMEOUT; 1829 // Can't delete op from mCurrentOperations here. waitUntilOperationComplete may be 1830 // called after we receive cancel here. We need this op's state there. 1831 1832 // Remove all pending timeout messages of types OP_TYPE_BACKUP_WAIT and 1833 // OP_TYPE_RESTORE_WAIT. On the other hand, OP_TYPE_BACKUP cannot time out and 1834 // doesn't require cancellation. 1835 if (op.type == OP_TYPE_BACKUP_WAIT || op.type == OP_TYPE_RESTORE_WAIT) { 1836 mBackupHandler.removeMessages(getMessageIdForOperationType(op.type)); 1837 } 1838 } 1839 mCurrentOpLock.notifyAll(); 1840 } 1841 1842 // If there's a TimeoutHandler for this event, call it 1843 if (op != null && op.callback != null) { 1844 if (MORE_DEBUG) { 1845 Slog.v(TAG, " Invoking cancel on " + op.callback); 1846 } 1847 op.callback.handleCancel(cancelAll); 1848 } 1849 } 1850 1851 // ----- Back up a set of applications via a worker thread ----- 1852 1853 public boolean isBackupOperationInProgress() { 1854 synchronized (mCurrentOpLock) { 1855 for (int i = 0; i < mCurrentOperations.size(); i++) { 1856 Operation op = mCurrentOperations.valueAt(i); 1857 if (op.type == OP_TYPE_BACKUP && op.state == OP_PENDING) { 1858 return true; 1859 } 1860 } 1861 } 1862 return false; 1863 } 1864 1865 1866 @Override 1867 public void tearDownAgentAndKill(ApplicationInfo app) { 1868 if (app == null) { 1869 // Null means the system package, so just quietly move on. :) 1870 return; 1871 } 1872 1873 try { 1874 // unbind and tidy up even on timeout or failure, just in case 1875 mActivityManager.unbindBackupAgent(app); 1876 1877 // The agent was running with a stub Application object, so shut it down. 1878 // !!! We hardcode the confirmation UI's package name here rather than use a 1879 // manifest flag! TODO something less direct. 1880 if (app.uid >= Process.FIRST_APPLICATION_UID 1881 && !app.packageName.equals("com.android.backupconfirm")) { 1882 if (MORE_DEBUG) Slog.d(TAG, "Killing agent host process"); 1883 mActivityManager.killApplicationProcess(app.processName, app.uid); 1884 } else { 1885 if (MORE_DEBUG) Slog.d(TAG, "Not killing after operation: " + app.processName); 1886 } 1887 } catch (RemoteException e) { 1888 Slog.d(TAG, "Lost app trying to shut down"); 1889 } 1890 } 1891 1892 public boolean deviceIsEncrypted() { 1893 try { 1894 return mStorageManager.getEncryptionState() 1895 != StorageManager.ENCRYPTION_STATE_NONE 1896 && mStorageManager.getPasswordType() 1897 != StorageManager.CRYPT_TYPE_DEFAULT; 1898 } catch (Exception e) { 1899 // If we can't talk to the storagemanager service we have a serious problem; fail 1900 // "secure" i.e. assuming that the device is encrypted. 1901 Slog.e(TAG, "Unable to communicate with storagemanager service: " + e.getMessage()); 1902 return true; 1903 } 1904 } 1905 1906 // ----- Full-data backup scheduling ----- 1907 1908 /** 1909 * Schedule a job to tell us when it's a good time to run a full backup 1910 */ 1911 public void scheduleNextFullBackupJob(long transportMinLatency) { 1912 synchronized (mQueueLock) { 1913 if (mFullBackupQueue.size() > 0) { 1914 // schedule the next job at the point in the future when the least-recently 1915 // backed up app comes due for backup again; or immediately if it's already 1916 // due. 1917 final long upcomingLastBackup = mFullBackupQueue.get(0).lastBackup; 1918 final long timeSinceLast = System.currentTimeMillis() - upcomingLastBackup; 1919 final long interval = mConstants.getFullBackupIntervalMilliseconds(); 1920 final long appLatency = (timeSinceLast < interval) ? (interval - timeSinceLast) : 0; 1921 final long latency = Math.max(transportMinLatency, appLatency); 1922 Runnable r = new Runnable() { 1923 @Override 1924 public void run() { 1925 FullBackupJob.schedule(mContext, latency, mConstants); 1926 } 1927 }; 1928 mBackupHandler.postDelayed(r, 2500); 1929 } else { 1930 if (DEBUG_SCHEDULING) { 1931 Slog.i(TAG, "Full backup queue empty; not scheduling"); 1932 } 1933 } 1934 } 1935 } 1936 1937 /** 1938 * Remove a package from the full-data queue. 1939 */ 1940 @GuardedBy("mQueueLock") 1941 private void dequeueFullBackupLocked(String packageName) { 1942 final int N = mFullBackupQueue.size(); 1943 for (int i = N - 1; i >= 0; i--) { 1944 final FullBackupEntry e = mFullBackupQueue.get(i); 1945 if (packageName.equals(e.packageName)) { 1946 mFullBackupQueue.remove(i); 1947 } 1948 } 1949 } 1950 1951 /** 1952 * Enqueue full backup for the given app, with a note about when it last ran. 1953 */ 1954 public void enqueueFullBackup(String packageName, long lastBackedUp) { 1955 FullBackupEntry newEntry = new FullBackupEntry(packageName, lastBackedUp); 1956 synchronized (mQueueLock) { 1957 // First, sanity check that we aren't adding a duplicate. Slow but 1958 // straightforward; we'll have at most on the order of a few hundred 1959 // items in this list. 1960 dequeueFullBackupLocked(packageName); 1961 1962 // This is also slow but easy for modest numbers of apps: work backwards 1963 // from the end of the queue until we find an item whose last backup 1964 // time was before this one, then insert this new entry after it. If we're 1965 // adding something new we don't bother scanning, and just prepend. 1966 int which = -1; 1967 if (lastBackedUp > 0) { 1968 for (which = mFullBackupQueue.size() - 1; which >= 0; which--) { 1969 final FullBackupEntry entry = mFullBackupQueue.get(which); 1970 if (entry.lastBackup <= lastBackedUp) { 1971 mFullBackupQueue.add(which + 1, newEntry); 1972 break; 1973 } 1974 } 1975 } 1976 if (which < 0) { 1977 // this one is earlier than any existing one, so prepend 1978 mFullBackupQueue.add(0, newEntry); 1979 } 1980 } 1981 writeFullBackupScheduleAsync(); 1982 } 1983 1984 private boolean fullBackupAllowable(String transportName) { 1985 if (!mTransportManager.isTransportRegistered(transportName)) { 1986 Slog.w(TAG, "Transport not registered; full data backup not performed"); 1987 return false; 1988 } 1989 1990 // Don't proceed unless we have already established package metadata 1991 // for the current dataset via a key/value backup pass. 1992 try { 1993 String transportDirName = mTransportManager.getTransportDirName(transportName); 1994 File stateDir = new File(mBaseStateDir, transportDirName); 1995 File pmState = new File(stateDir, PACKAGE_MANAGER_SENTINEL); 1996 if (pmState.length() <= 0) { 1997 if (DEBUG) { 1998 Slog.i(TAG, "Full backup requested but dataset not yet initialized"); 1999 } 2000 return false; 2001 } 2002 } catch (Exception e) { 2003 Slog.w(TAG, "Unable to get transport name: " + e.getMessage()); 2004 return false; 2005 } 2006 2007 return true; 2008 } 2009 2010 /** 2011 * Conditions are right for a full backup operation, so run one. The model we use is 2012 * to perform one app backup per scheduled job execution, and to reschedule the job 2013 * with zero latency as long as conditions remain right and we still have work to do. 2014 * 2015 * <p>This is the "start a full backup operation" entry point called by the scheduled job. 2016 * 2017 * @return Whether ongoing work will continue. The return value here will be passed 2018 * along as the return value to the scheduled job's onStartJob() callback. 2019 */ 2020 @Override 2021 public boolean beginFullBackup(FullBackupJob scheduledJob) { 2022 final long now = System.currentTimeMillis(); 2023 final long fullBackupInterval; 2024 final long keyValueBackupInterval; 2025 synchronized (mConstants) { 2026 fullBackupInterval = mConstants.getFullBackupIntervalMilliseconds(); 2027 keyValueBackupInterval = mConstants.getKeyValueBackupIntervalMilliseconds(); 2028 } 2029 FullBackupEntry entry = null; 2030 long latency = fullBackupInterval; 2031 2032 if (!mEnabled || !mProvisioned) { 2033 // Backups are globally disabled, so don't proceed. We also don't reschedule 2034 // the job driving automatic backups; that job will be scheduled again when 2035 // the user enables backup. 2036 if (MORE_DEBUG) { 2037 Slog.i(TAG, "beginFullBackup but e=" + mEnabled 2038 + " p=" + mProvisioned + "; ignoring"); 2039 } 2040 return false; 2041 } 2042 2043 // Don't run the backup if we're in battery saver mode, but reschedule 2044 // to try again in the not-so-distant future. 2045 final PowerSaveState result = 2046 mPowerManager.getPowerSaveState(ServiceType.FULL_BACKUP); 2047 if (result.batterySaverEnabled) { 2048 if (DEBUG) Slog.i(TAG, "Deferring scheduled full backups in battery saver mode"); 2049 FullBackupJob.schedule(mContext, keyValueBackupInterval, mConstants); 2050 return false; 2051 } 2052 2053 if (DEBUG_SCHEDULING) { 2054 Slog.i(TAG, "Beginning scheduled full backup operation"); 2055 } 2056 2057 // Great; we're able to run full backup jobs now. See if we have any work to do. 2058 synchronized (mQueueLock) { 2059 if (mRunningFullBackupTask != null) { 2060 Slog.e(TAG, "Backup triggered but one already/still running!"); 2061 return false; 2062 } 2063 2064 // At this point we think that we have work to do, but possibly not right now. 2065 // Any exit without actually running backups will also require that we 2066 // reschedule the job. 2067 boolean runBackup = true; 2068 boolean headBusy; 2069 2070 do { 2071 // Recheck each time, because culling due to ineligibility may 2072 // have emptied the queue. 2073 if (mFullBackupQueue.size() == 0) { 2074 // no work to do so just bow out 2075 if (DEBUG) { 2076 Slog.i(TAG, "Backup queue empty; doing nothing"); 2077 } 2078 runBackup = false; 2079 break; 2080 } 2081 2082 headBusy = false; 2083 2084 String transportName = mTransportManager.getCurrentTransportName(); 2085 if (!fullBackupAllowable(transportName)) { 2086 if (MORE_DEBUG) { 2087 Slog.i(TAG, "Preconditions not met; not running full backup"); 2088 } 2089 runBackup = false; 2090 // Typically this means we haven't run a key/value backup yet. Back off 2091 // full-backup operations by the key/value job's run interval so that 2092 // next time we run, we are likely to be able to make progress. 2093 latency = keyValueBackupInterval; 2094 } 2095 2096 if (runBackup) { 2097 entry = mFullBackupQueue.get(0); 2098 long timeSinceRun = now - entry.lastBackup; 2099 runBackup = (timeSinceRun >= fullBackupInterval); 2100 if (!runBackup) { 2101 // It's too early to back up the next thing in the queue, so bow out 2102 if (MORE_DEBUG) { 2103 Slog.i(TAG, "Device ready but too early to back up next app"); 2104 } 2105 // Wait until the next app in the queue falls due for a full data backup 2106 latency = fullBackupInterval - timeSinceRun; 2107 break; // we know we aren't doing work yet, so bail. 2108 } 2109 2110 try { 2111 PackageInfo appInfo = mPackageManager.getPackageInfo(entry.packageName, 0); 2112 if (!AppBackupUtils.appGetsFullBackup(appInfo)) { 2113 // The head app isn't supposed to get full-data backups [any more]; 2114 // so we cull it and force a loop around to consider the new head 2115 // app. 2116 if (MORE_DEBUG) { 2117 Slog.i(TAG, "Culling package " + entry.packageName 2118 + " in full-backup queue but not eligible"); 2119 } 2120 mFullBackupQueue.remove(0); 2121 headBusy = true; // force the while() condition 2122 continue; 2123 } 2124 2125 final int privFlags = appInfo.applicationInfo.privateFlags; 2126 headBusy = (privFlags & PRIVATE_FLAG_BACKUP_IN_FOREGROUND) == 0 2127 && mActivityManager.isAppForeground(appInfo.applicationInfo.uid); 2128 2129 if (headBusy) { 2130 final long nextEligible = System.currentTimeMillis() 2131 + BUSY_BACKOFF_MIN_MILLIS 2132 + mTokenGenerator.nextInt(BUSY_BACKOFF_FUZZ); 2133 if (DEBUG_SCHEDULING) { 2134 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 2135 Slog.i(TAG, "Full backup time but " + entry.packageName 2136 + " is busy; deferring to " 2137 + sdf.format(new Date(nextEligible))); 2138 } 2139 // This relocates the app's entry from the head of the queue to 2140 // its order-appropriate position further down, so upon looping 2141 // a new candidate will be considered at the head. 2142 enqueueFullBackup(entry.packageName, nextEligible - fullBackupInterval); 2143 } 2144 } catch (NameNotFoundException nnf) { 2145 // So, we think we want to back this up, but it turns out the package 2146 // in question is no longer installed. We want to drop it from the 2147 // queue entirely and move on, but if there's nothing else in the queue 2148 // we should bail entirely. headBusy cannot have been set to true yet. 2149 runBackup = (mFullBackupQueue.size() > 1); 2150 } catch (RemoteException e) { 2151 // Cannot happen; the Activity Manager is in the same process 2152 } 2153 } 2154 } while (headBusy); 2155 2156 if (!runBackup) { 2157 if (DEBUG_SCHEDULING) { 2158 Slog.i(TAG, "Nothing pending full backup; rescheduling +" + latency); 2159 } 2160 final long deferTime = latency; // pin for the closure 2161 mBackupHandler.post(new Runnable() { 2162 @Override 2163 public void run() { 2164 FullBackupJob.schedule(mContext, deferTime, mConstants); 2165 } 2166 }); 2167 return false; 2168 } 2169 2170 // Okay, the top thing is ready for backup now. Do it. 2171 mFullBackupQueue.remove(0); 2172 CountDownLatch latch = new CountDownLatch(1); 2173 String[] pkg = new String[]{entry.packageName}; 2174 mRunningFullBackupTask = PerformFullTransportBackupTask.newWithCurrentTransport( 2175 this, 2176 /* observer */ null, 2177 pkg, 2178 /* updateSchedule */ true, 2179 scheduledJob, 2180 latch, 2181 /* backupObserver */ null, 2182 /* monitor */ null, 2183 /* userInitiated */ false, 2184 "BMS.beginFullBackup()"); 2185 // Acquiring wakelock for PerformFullTransportBackupTask before its start. 2186 mWakelock.acquire(); 2187 (new Thread(mRunningFullBackupTask)).start(); 2188 } 2189 2190 return true; 2191 } 2192 2193 // The job scheduler says our constraints don't hold any more, 2194 // so tear down any ongoing backup task right away. 2195 @Override 2196 public void endFullBackup() { 2197 // offload the mRunningFullBackupTask.handleCancel() call to another thread, 2198 // as we might have to wait for mCancelLock 2199 Runnable endFullBackupRunnable = new Runnable() { 2200 @Override 2201 public void run() { 2202 PerformFullTransportBackupTask pftbt = null; 2203 synchronized (mQueueLock) { 2204 if (mRunningFullBackupTask != null) { 2205 pftbt = mRunningFullBackupTask; 2206 } 2207 } 2208 if (pftbt != null) { 2209 if (DEBUG_SCHEDULING) { 2210 Slog.i(TAG, "Telling running backup to stop"); 2211 } 2212 pftbt.handleCancel(true); 2213 } 2214 } 2215 }; 2216 new Thread(endFullBackupRunnable, "end-full-backup").start(); 2217 } 2218 2219 // Used by both incremental and full restore 2220 public void restoreWidgetData(String packageName, byte[] widgetData) { 2221 // Apply the restored widget state and generate the ID update for the app 2222 // TODO: http://b/22388012 2223 if (MORE_DEBUG) { 2224 Slog.i(TAG, "Incorporating restored widget data"); 2225 } 2226 AppWidgetBackupBridge.restoreWidgetState(packageName, widgetData, UserHandle.USER_SYSTEM); 2227 } 2228 2229 // ***************************** 2230 // NEW UNIFIED RESTORE IMPLEMENTATION 2231 // ***************************** 2232 2233 public void dataChangedImpl(String packageName) { 2234 HashSet<String> targets = dataChangedTargets(packageName); 2235 dataChangedImpl(packageName, targets); 2236 } 2237 2238 private void dataChangedImpl(String packageName, HashSet<String> targets) { 2239 // Record that we need a backup pass for the caller. Since multiple callers 2240 // may share a uid, we need to note all candidates within that uid and schedule 2241 // a backup pass for each of them. 2242 if (targets == null) { 2243 Slog.w(TAG, "dataChanged but no participant pkg='" + packageName + "'" 2244 + " uid=" + Binder.getCallingUid()); 2245 return; 2246 } 2247 2248 synchronized (mQueueLock) { 2249 // Note that this client has made data changes that need to be backed up 2250 if (targets.contains(packageName)) { 2251 // Add the caller to the set of pending backups. If there is 2252 // one already there, then overwrite it, but no harm done. 2253 BackupRequest req = new BackupRequest(packageName); 2254 if (mPendingBackups.put(packageName, req) == null) { 2255 if (MORE_DEBUG) Slog.d(TAG, "Now staging backup of " + packageName); 2256 2257 // Journal this request in case of crash. The put() 2258 // operation returned null when this package was not already 2259 // in the set; we want to avoid touching the disk redundantly. 2260 writeToJournalLocked(packageName); 2261 } 2262 } 2263 } 2264 2265 // ...and schedule a backup pass if necessary 2266 KeyValueBackupJob.schedule(mContext, mConstants); 2267 } 2268 2269 // Note: packageName is currently unused, but may be in the future 2270 private HashSet<String> dataChangedTargets(String packageName) { 2271 // If the caller does not hold the BACKUP permission, it can only request a 2272 // backup of its own data. 2273 if ((mContext.checkPermission(android.Manifest.permission.BACKUP, Binder.getCallingPid(), 2274 Binder.getCallingUid())) == PackageManager.PERMISSION_DENIED) { 2275 synchronized (mBackupParticipants) { 2276 return mBackupParticipants.get(Binder.getCallingUid()); 2277 } 2278 } 2279 2280 // a caller with full permission can ask to back up any participating app 2281 if (PACKAGE_MANAGER_SENTINEL.equals(packageName)) { 2282 return Sets.newHashSet(PACKAGE_MANAGER_SENTINEL); 2283 } else { 2284 synchronized (mBackupParticipants) { 2285 return SparseArrayUtils.union(mBackupParticipants); 2286 } 2287 } 2288 } 2289 2290 private void writeToJournalLocked(String str) { 2291 try { 2292 if (mJournal == null) mJournal = DataChangedJournal.newJournal(mJournalDir); 2293 mJournal.addPackage(str); 2294 } catch (IOException e) { 2295 Slog.e(TAG, "Can't write " + str + " to backup journal", e); 2296 mJournal = null; 2297 } 2298 } 2299 2300 // ----- IBackupManager binder interface ----- 2301 2302 @Override 2303 public void dataChanged(final String packageName) { 2304 final int callingUserHandle = UserHandle.getCallingUserId(); 2305 if (callingUserHandle != UserHandle.USER_SYSTEM) { 2306 // TODO: http://b/22388012 2307 // App is running under a non-owner user profile. For now, we do not back 2308 // up data from secondary user profiles. 2309 // TODO: backups for all user profiles although don't add backup for profiles 2310 // without adding admin control in DevicePolicyManager. 2311 if (MORE_DEBUG) { 2312 Slog.v(TAG, "dataChanged(" + packageName + ") ignored because it's user " 2313 + callingUserHandle); 2314 } 2315 return; 2316 } 2317 2318 final HashSet<String> targets = dataChangedTargets(packageName); 2319 if (targets == null) { 2320 Slog.w(TAG, "dataChanged but no participant pkg='" + packageName + "'" 2321 + " uid=" + Binder.getCallingUid()); 2322 return; 2323 } 2324 2325 mBackupHandler.post(new Runnable() { 2326 public void run() { 2327 dataChangedImpl(packageName, targets); 2328 } 2329 }); 2330 } 2331 2332 // Run an initialize operation for the given transport 2333 @Override 2334 public void initializeTransports(String[] transportNames, IBackupObserver observer) { 2335 mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, 2336 "initializeTransport"); 2337 if (MORE_DEBUG || true) { 2338 Slog.v(TAG, "initializeTransport(): " + Arrays.asList(transportNames)); 2339 } 2340 2341 final long oldId = Binder.clearCallingIdentity(); 2342 try { 2343 mWakelock.acquire(); 2344 OnTaskFinishedListener listener = caller -> mWakelock.release(); 2345 mBackupHandler.post( 2346 new PerformInitializeTask(this, transportNames, observer, listener)); 2347 } finally { 2348 Binder.restoreCallingIdentity(oldId); 2349 } 2350 } 2351 2352 // Clear the given package's backup data from the current transport 2353 @Override 2354 public void clearBackupData(String transportName, String packageName) { 2355 if (DEBUG) Slog.v(TAG, "clearBackupData() of " + packageName + " on " + transportName); 2356 PackageInfo info; 2357 try { 2358 info = mPackageManager.getPackageInfo(packageName, 2359 PackageManager.GET_SIGNING_CERTIFICATES); 2360 } catch (NameNotFoundException e) { 2361 Slog.d(TAG, "No such package '" + packageName + "' - not clearing backup data"); 2362 return; 2363 } 2364 2365 // If the caller does not hold the BACKUP permission, it can only request a 2366 // wipe of its own backed-up data. 2367 Set<String> apps; 2368 if ((mContext.checkPermission(android.Manifest.permission.BACKUP, Binder.getCallingPid(), 2369 Binder.getCallingUid())) == PackageManager.PERMISSION_DENIED) { 2370 apps = mBackupParticipants.get(Binder.getCallingUid()); 2371 } else { 2372 // a caller with full permission can ask to back up any participating app 2373 // !!! TODO: allow data-clear of ANY app? 2374 if (MORE_DEBUG) Slog.v(TAG, "Privileged caller, allowing clear of other apps"); 2375 apps = mProcessedPackagesJournal.getPackagesCopy(); 2376 } 2377 2378 if (apps.contains(packageName)) { 2379 // found it; fire off the clear request 2380 if (MORE_DEBUG) Slog.v(TAG, "Found the app - running clear process"); 2381 mBackupHandler.removeMessages(MSG_RETRY_CLEAR); 2382 synchronized (mQueueLock) { 2383 TransportClient transportClient = 2384 mTransportManager 2385 .getTransportClient(transportName, "BMS.clearBackupData()"); 2386 if (transportClient == null) { 2387 // transport is currently unregistered -- make sure to retry 2388 Message msg = mBackupHandler.obtainMessage(MSG_RETRY_CLEAR, 2389 new ClearRetryParams(transportName, packageName)); 2390 mBackupHandler.sendMessageDelayed(msg, TRANSPORT_RETRY_INTERVAL); 2391 return; 2392 } 2393 long oldId = Binder.clearCallingIdentity(); 2394 OnTaskFinishedListener listener = 2395 caller -> 2396 mTransportManager.disposeOfTransportClient(transportClient, caller); 2397 mWakelock.acquire(); 2398 Message msg = mBackupHandler.obtainMessage( 2399 MSG_RUN_CLEAR, 2400 new ClearParams(transportClient, info, listener)); 2401 mBackupHandler.sendMessage(msg); 2402 Binder.restoreCallingIdentity(oldId); 2403 } 2404 } 2405 } 2406 2407 // Run a backup pass immediately for any applications that have declared 2408 // that they have pending updates. 2409 @Override 2410 public void backupNow() { 2411 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "backupNow"); 2412 2413 final PowerSaveState result = 2414 mPowerManager.getPowerSaveState(ServiceType.KEYVALUE_BACKUP); 2415 if (result.batterySaverEnabled) { 2416 if (DEBUG) Slog.v(TAG, "Not running backup while in battery save mode"); 2417 KeyValueBackupJob.schedule(mContext, mConstants); // try again in several hours 2418 } else { 2419 if (DEBUG) Slog.v(TAG, "Scheduling immediate backup pass"); 2420 synchronized (mQueueLock) { 2421 // Fire the intent that kicks off the whole shebang... 2422 try { 2423 mRunBackupIntent.send(); 2424 } catch (PendingIntent.CanceledException e) { 2425 // should never happen 2426 Slog.e(TAG, "run-backup intent cancelled!"); 2427 } 2428 2429 // ...and cancel any pending scheduled job, because we've just superseded it 2430 KeyValueBackupJob.cancel(mContext); 2431 } 2432 } 2433 } 2434 2435 public boolean deviceIsProvisioned() { 2436 final ContentResolver resolver = mContext.getContentResolver(); 2437 return (Settings.Global.getInt(resolver, Settings.Global.DEVICE_PROVISIONED, 0) != 0); 2438 } 2439 2440 // Run a backup pass for the given packages, writing the resulting data stream 2441 // to the supplied file descriptor. This method is synchronous and does not return 2442 // to the caller until the backup has been completed. 2443 // 2444 // This is the variant used by 'adb backup'; it requires on-screen confirmation 2445 // by the user because it can be used to offload data over untrusted USB. 2446 @Override 2447 public void adbBackup(ParcelFileDescriptor fd, boolean includeApks, boolean includeObbs, 2448 boolean includeShared, boolean doWidgets, boolean doAllApps, boolean includeSystem, 2449 boolean compress, boolean doKeyValue, String[] pkgList) { 2450 mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "adbBackup"); 2451 2452 final int callingUserHandle = UserHandle.getCallingUserId(); 2453 // TODO: http://b/22388012 2454 if (callingUserHandle != UserHandle.USER_SYSTEM) { 2455 throw new IllegalStateException("Backup supported only for the device owner"); 2456 } 2457 2458 // Validate 2459 if (!doAllApps) { 2460 if (!includeShared) { 2461 // If we're backing up shared data (sdcard or equivalent), then we can run 2462 // without any supplied app names. Otherwise, we'd be doing no work, so 2463 // report the error. 2464 if (pkgList == null || pkgList.length == 0) { 2465 throw new IllegalArgumentException( 2466 "Backup requested but neither shared nor any apps named"); 2467 } 2468 } 2469 } 2470 2471 long oldId = Binder.clearCallingIdentity(); 2472 try { 2473 // Doesn't make sense to do a full backup prior to setup 2474 if (!deviceIsProvisioned()) { 2475 Slog.i(TAG, "Backup not supported before setup"); 2476 return; 2477 } 2478 2479 if (DEBUG) { 2480 Slog.v(TAG, "Requesting backup: apks=" + includeApks + " obb=" + includeObbs 2481 + " shared=" + includeShared + " all=" + doAllApps + " system=" 2482 + includeSystem + " includekeyvalue=" + doKeyValue + " pkgs=" + pkgList); 2483 } 2484 Slog.i(TAG, "Beginning adb backup..."); 2485 2486 AdbBackupParams params = new AdbBackupParams(fd, includeApks, includeObbs, 2487 includeShared, doWidgets, doAllApps, includeSystem, compress, doKeyValue, 2488 pkgList); 2489 final int token = generateRandomIntegerToken(); 2490 synchronized (mAdbBackupRestoreConfirmations) { 2491 mAdbBackupRestoreConfirmations.put(token, params); 2492 } 2493 2494 // start up the confirmation UI 2495 if (DEBUG) Slog.d(TAG, "Starting backup confirmation UI, token=" + token); 2496 if (!startConfirmationUi(token, FullBackup.FULL_BACKUP_INTENT_ACTION)) { 2497 Slog.e(TAG, "Unable to launch backup confirmation UI"); 2498 mAdbBackupRestoreConfirmations.delete(token); 2499 return; 2500 } 2501 2502 // make sure the screen is lit for the user interaction 2503 mPowerManager.userActivity(SystemClock.uptimeMillis(), 2504 PowerManager.USER_ACTIVITY_EVENT_OTHER, 2505 0); 2506 2507 // start the confirmation countdown 2508 startConfirmationTimeout(token, params); 2509 2510 // wait for the backup to be performed 2511 if (DEBUG) Slog.d(TAG, "Waiting for backup completion..."); 2512 waitForCompletion(params); 2513 } finally { 2514 try { 2515 fd.close(); 2516 } catch (IOException e) { 2517 Slog.e(TAG, "IO error closing output for adb backup: " + e.getMessage()); 2518 } 2519 Binder.restoreCallingIdentity(oldId); 2520 Slog.d(TAG, "Adb backup processing complete."); 2521 } 2522 } 2523 2524 @Override 2525 public void fullTransportBackup(String[] pkgNames) { 2526 mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, 2527 "fullTransportBackup"); 2528 2529 final int callingUserHandle = UserHandle.getCallingUserId(); 2530 // TODO: http://b/22388012 2531 if (callingUserHandle != UserHandle.USER_SYSTEM) { 2532 throw new IllegalStateException("Restore supported only for the device owner"); 2533 } 2534 2535 String transportName = mTransportManager.getCurrentTransportName(); 2536 if (!fullBackupAllowable(transportName)) { 2537 Slog.i(TAG, "Full backup not currently possible -- key/value backup not yet run?"); 2538 } else { 2539 if (DEBUG) { 2540 Slog.d(TAG, "fullTransportBackup()"); 2541 } 2542 2543 final long oldId = Binder.clearCallingIdentity(); 2544 try { 2545 CountDownLatch latch = new CountDownLatch(1); 2546 Runnable task = PerformFullTransportBackupTask.newWithCurrentTransport( 2547 this, 2548 /* observer */ null, 2549 pkgNames, 2550 /* updateSchedule */ false, 2551 /* runningJob */ null, 2552 latch, 2553 /* backupObserver */ null, 2554 /* monitor */ null, 2555 /* userInitiated */ false, 2556 "BMS.fullTransportBackup()"); 2557 // Acquiring wakelock for PerformFullTransportBackupTask before its start. 2558 mWakelock.acquire(); 2559 (new Thread(task, "full-transport-master")).start(); 2560 do { 2561 try { 2562 latch.await(); 2563 break; 2564 } catch (InterruptedException e) { 2565 // Just go back to waiting for the latch to indicate completion 2566 } 2567 } while (true); 2568 2569 // We just ran a backup on these packages, so kick them to the end of the queue 2570 final long now = System.currentTimeMillis(); 2571 for (String pkg : pkgNames) { 2572 enqueueFullBackup(pkg, now); 2573 } 2574 } finally { 2575 Binder.restoreCallingIdentity(oldId); 2576 } 2577 } 2578 2579 if (DEBUG) { 2580 Slog.d(TAG, "Done with full transport backup."); 2581 } 2582 } 2583 2584 @Override 2585 public void adbRestore(ParcelFileDescriptor fd) { 2586 mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "adbRestore"); 2587 2588 final int callingUserHandle = UserHandle.getCallingUserId(); 2589 // TODO: http://b/22388012 2590 if (callingUserHandle != UserHandle.USER_SYSTEM) { 2591 throw new IllegalStateException("Restore supported only for the device owner"); 2592 } 2593 2594 long oldId = Binder.clearCallingIdentity(); 2595 2596 try { 2597 // Check whether the device has been provisioned -- we don't handle 2598 // full restores prior to completing the setup process. 2599 if (!deviceIsProvisioned()) { 2600 Slog.i(TAG, "Full restore not permitted before setup"); 2601 return; 2602 } 2603 2604 Slog.i(TAG, "Beginning restore..."); 2605 2606 AdbRestoreParams params = new AdbRestoreParams(fd); 2607 final int token = generateRandomIntegerToken(); 2608 synchronized (mAdbBackupRestoreConfirmations) { 2609 mAdbBackupRestoreConfirmations.put(token, params); 2610 } 2611 2612 // start up the confirmation UI 2613 if (DEBUG) Slog.d(TAG, "Starting restore confirmation UI, token=" + token); 2614 if (!startConfirmationUi(token, FullBackup.FULL_RESTORE_INTENT_ACTION)) { 2615 Slog.e(TAG, "Unable to launch restore confirmation"); 2616 mAdbBackupRestoreConfirmations.delete(token); 2617 return; 2618 } 2619 2620 // make sure the screen is lit for the user interaction 2621 mPowerManager.userActivity(SystemClock.uptimeMillis(), 2622 PowerManager.USER_ACTIVITY_EVENT_OTHER, 2623 0); 2624 2625 // start the confirmation countdown 2626 startConfirmationTimeout(token, params); 2627 2628 // wait for the restore to be performed 2629 if (DEBUG) Slog.d(TAG, "Waiting for restore completion..."); 2630 waitForCompletion(params); 2631 } finally { 2632 try { 2633 fd.close(); 2634 } catch (IOException e) { 2635 Slog.w(TAG, "Error trying to close fd after adb restore: " + e); 2636 } 2637 Binder.restoreCallingIdentity(oldId); 2638 Slog.i(TAG, "adb restore processing complete."); 2639 } 2640 } 2641 2642 private boolean startConfirmationUi(int token, String action) { 2643 try { 2644 Intent confIntent = new Intent(action); 2645 confIntent.setClassName("com.android.backupconfirm", 2646 "com.android.backupconfirm.BackupRestoreConfirmation"); 2647 confIntent.putExtra(FullBackup.CONF_TOKEN_INTENT_EXTRA, token); 2648 confIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); 2649 mContext.startActivityAsUser(confIntent, UserHandle.SYSTEM); 2650 } catch (ActivityNotFoundException e) { 2651 return false; 2652 } 2653 return true; 2654 } 2655 2656 private void startConfirmationTimeout(int token, AdbParams params) { 2657 if (MORE_DEBUG) { 2658 Slog.d(TAG, "Posting conf timeout msg after " 2659 + TIMEOUT_FULL_CONFIRMATION + " millis"); 2660 } 2661 Message msg = mBackupHandler.obtainMessage(MSG_FULL_CONFIRMATION_TIMEOUT, 2662 token, 0, params); 2663 mBackupHandler.sendMessageDelayed(msg, TIMEOUT_FULL_CONFIRMATION); 2664 } 2665 2666 private void waitForCompletion(AdbParams params) { 2667 synchronized (params.latch) { 2668 while (params.latch.get() == false) { 2669 try { 2670 params.latch.wait(); 2671 } catch (InterruptedException e) { /* never interrupted */ } 2672 } 2673 } 2674 } 2675 2676 public void signalAdbBackupRestoreCompletion(AdbParams params) { 2677 synchronized (params.latch) { 2678 params.latch.set(true); 2679 params.latch.notifyAll(); 2680 } 2681 } 2682 2683 // Confirm that the previously-requested full backup/restore operation can proceed. This 2684 // is used to require a user-facing disclosure about the operation. 2685 @Override 2686 public void acknowledgeAdbBackupOrRestore(int token, boolean allow, 2687 String curPassword, String encPpassword, IFullBackupRestoreObserver observer) { 2688 if (DEBUG) { 2689 Slog.d(TAG, "acknowledgeAdbBackupOrRestore : token=" + token 2690 + " allow=" + allow); 2691 } 2692 2693 // TODO: possibly require not just this signature-only permission, but even 2694 // require that the specific designated confirmation-UI app uid is the caller? 2695 mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, 2696 "acknowledgeAdbBackupOrRestore"); 2697 2698 long oldId = Binder.clearCallingIdentity(); 2699 try { 2700 2701 AdbParams params; 2702 synchronized (mAdbBackupRestoreConfirmations) { 2703 params = mAdbBackupRestoreConfirmations.get(token); 2704 if (params != null) { 2705 mBackupHandler.removeMessages(MSG_FULL_CONFIRMATION_TIMEOUT, params); 2706 mAdbBackupRestoreConfirmations.delete(token); 2707 2708 if (allow) { 2709 final int verb = params instanceof AdbBackupParams 2710 ? MSG_RUN_ADB_BACKUP 2711 : MSG_RUN_ADB_RESTORE; 2712 2713 params.observer = observer; 2714 params.curPassword = curPassword; 2715 2716 params.encryptPassword = encPpassword; 2717 2718 if (MORE_DEBUG) Slog.d(TAG, "Sending conf message with verb " + verb); 2719 mWakelock.acquire(); 2720 Message msg = mBackupHandler.obtainMessage(verb, params); 2721 mBackupHandler.sendMessage(msg); 2722 } else { 2723 Slog.w(TAG, "User rejected full backup/restore operation"); 2724 // indicate completion without having actually transferred any data 2725 signalAdbBackupRestoreCompletion(params); 2726 } 2727 } else { 2728 Slog.w(TAG, "Attempted to ack full backup/restore with invalid token"); 2729 } 2730 } 2731 } finally { 2732 Binder.restoreCallingIdentity(oldId); 2733 } 2734 } 2735 2736 private static boolean backupSettingMigrated(int userId) { 2737 File base = new File(Environment.getDataDirectory(), "backup"); 2738 File enableFile = new File(base, BACKUP_ENABLE_FILE); 2739 return enableFile.exists(); 2740 } 2741 2742 private static boolean readBackupEnableState(int userId) { 2743 File base = new File(Environment.getDataDirectory(), "backup"); 2744 File enableFile = new File(base, BACKUP_ENABLE_FILE); 2745 if (enableFile.exists()) { 2746 try (FileInputStream fin = new FileInputStream(enableFile)) { 2747 int state = fin.read(); 2748 return state != 0; 2749 } catch (IOException e) { 2750 // can't read the file; fall through to assume disabled 2751 Slog.e(TAG, "Cannot read enable state; assuming disabled"); 2752 } 2753 } else { 2754 if (DEBUG) { 2755 Slog.i(TAG, "isBackupEnabled() => false due to absent settings file"); 2756 } 2757 } 2758 return false; 2759 } 2760 2761 private static void writeBackupEnableState(boolean enable, int userId) { 2762 File base = new File(Environment.getDataDirectory(), "backup"); 2763 File enableFile = new File(base, BACKUP_ENABLE_FILE); 2764 File stage = new File(base, BACKUP_ENABLE_FILE + "-stage"); 2765 try (FileOutputStream fout = new FileOutputStream(stage)) { 2766 fout.write(enable ? 1 : 0); 2767 fout.close(); 2768 stage.renameTo(enableFile); 2769 // will be synced immediately by the try-with-resources call to close() 2770 } catch (IOException | RuntimeException e) { 2771 // Whoops; looks like we're doomed. Roll everything out, disabled, 2772 // including the legacy state. 2773 Slog.e(TAG, "Unable to record backup enable state; reverting to disabled: " 2774 + e.getMessage()); 2775 2776 final ContentResolver r = sInstance.mContext.getContentResolver(); 2777 Settings.Secure.putStringForUser(r, 2778 Settings.Secure.BACKUP_ENABLED, null, userId); 2779 enableFile.delete(); 2780 stage.delete(); 2781 } 2782 } 2783 2784 // Enable/disable backups 2785 @Override 2786 public void setBackupEnabled(boolean enable) { 2787 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, 2788 "setBackupEnabled"); 2789 if (!enable && mBackupPolicyEnforcer.getMandatoryBackupTransport() != null) { 2790 Slog.w(TAG, "Cannot disable backups when the mandatory backups policy is active."); 2791 return; 2792 } 2793 2794 Slog.i(TAG, "Backup enabled => " + enable); 2795 2796 long oldId = Binder.clearCallingIdentity(); 2797 try { 2798 boolean wasEnabled = mEnabled; 2799 synchronized (this) { 2800 writeBackupEnableState(enable, UserHandle.USER_SYSTEM); 2801 mEnabled = enable; 2802 } 2803 2804 synchronized (mQueueLock) { 2805 if (enable && !wasEnabled && mProvisioned) { 2806 // if we've just been enabled, start scheduling backup passes 2807 KeyValueBackupJob.schedule(mContext, mConstants); 2808 scheduleNextFullBackupJob(0); 2809 } else if (!enable) { 2810 // No longer enabled, so stop running backups 2811 if (MORE_DEBUG) Slog.i(TAG, "Opting out of backup"); 2812 2813 KeyValueBackupJob.cancel(mContext); 2814 2815 // This also constitutes an opt-out, so we wipe any data for 2816 // this device from the backend. We start that process with 2817 // an alarm in order to guarantee wakelock states. 2818 if (wasEnabled && mProvisioned) { 2819 // NOTE: we currently flush every registered transport, not just 2820 // the currently-active one. 2821 List<String> transportNames = new ArrayList<>(); 2822 List<String> transportDirNames = new ArrayList<>(); 2823 mTransportManager.forEachRegisteredTransport( 2824 name -> { 2825 final String dirName; 2826 try { 2827 dirName = 2828 mTransportManager 2829 .getTransportDirName(name); 2830 } catch (TransportNotRegisteredException e) { 2831 // Should never happen 2832 Slog.e(TAG, "Unexpected unregistered transport", e); 2833 return; 2834 } 2835 transportNames.add(name); 2836 transportDirNames.add(dirName); 2837 }); 2838 2839 // build the set of transports for which we are posting an init 2840 for (int i = 0; i < transportNames.size(); i++) { 2841 recordInitPending( 2842 true, 2843 transportNames.get(i), 2844 transportDirNames.get(i)); 2845 } 2846 mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 2847 mRunInitIntent); 2848 } 2849 } 2850 } 2851 } finally { 2852 Binder.restoreCallingIdentity(oldId); 2853 } 2854 } 2855 2856 // Enable/disable automatic restore of app data at install time 2857 @Override 2858 public void setAutoRestore(boolean doAutoRestore) { 2859 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, 2860 "setAutoRestore"); 2861 2862 Slog.i(TAG, "Auto restore => " + doAutoRestore); 2863 2864 final long oldId = Binder.clearCallingIdentity(); 2865 try { 2866 synchronized (this) { 2867 Settings.Secure.putInt(mContext.getContentResolver(), 2868 Settings.Secure.BACKUP_AUTO_RESTORE, doAutoRestore ? 1 : 0); 2869 mAutoRestore = doAutoRestore; 2870 } 2871 } finally { 2872 Binder.restoreCallingIdentity(oldId); 2873 } 2874 } 2875 2876 // Mark the backup service as having been provisioned 2877 @Override 2878 public void setBackupProvisioned(boolean available) { 2879 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, 2880 "setBackupProvisioned"); 2881 /* 2882 * This is now a no-op; provisioning is simply the device's own setup state. 2883 */ 2884 } 2885 2886 // Report whether the backup mechanism is currently enabled 2887 @Override 2888 public boolean isBackupEnabled() { 2889 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, 2890 "isBackupEnabled"); 2891 return mEnabled; // no need to synchronize just to read it 2892 } 2893 2894 // Report the name of the currently active transport 2895 @Override 2896 public String getCurrentTransport() { 2897 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, 2898 "getCurrentTransport"); 2899 String currentTransport = mTransportManager.getCurrentTransportName(); 2900 if (MORE_DEBUG) Slog.v(TAG, "... getCurrentTransport() returning " + currentTransport); 2901 return currentTransport; 2902 } 2903 2904 // Report all known, available backup transports 2905 @Override 2906 public String[] listAllTransports() { 2907 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, 2908 "listAllTransports"); 2909 2910 return mTransportManager.getRegisteredTransportNames(); 2911 } 2912 2913 @Override 2914 public ComponentName[] listAllTransportComponents() { 2915 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, 2916 "listAllTransportComponents"); 2917 return mTransportManager.getRegisteredTransportComponents(); 2918 } 2919 2920 @Override 2921 public String[] getTransportWhitelist() { 2922 // No permission check, intentionally. 2923 Set<ComponentName> whitelistedComponents = mTransportManager.getTransportWhitelist(); 2924 String[] whitelistedTransports = new String[whitelistedComponents.size()]; 2925 int i = 0; 2926 for (ComponentName component : whitelistedComponents) { 2927 whitelistedTransports[i] = component.flattenToShortString(); 2928 i++; 2929 } 2930 return whitelistedTransports; 2931 } 2932 2933 /** 2934 * Update the attributes of the transport identified by {@code transportComponent}. If the 2935 * specified transport has not been bound at least once (for registration), this call will be 2936 * ignored. Only the host process of the transport can change its description, otherwise a 2937 * {@link SecurityException} will be thrown. 2938 * 2939 * @param transportComponent The identity of the transport being described. 2940 * @param name A {@link String} with the new name for the transport. This is NOT for 2941 * identification. MUST NOT be {@code null}. 2942 * @param configurationIntent An {@link Intent} that can be passed to 2943 * {@link Context#startActivity} in order to launch the transport's configuration UI. It may 2944 * be {@code null} if the transport does not offer any user-facing configuration UI. 2945 * @param currentDestinationString A {@link String} describing the destination to which the 2946 * transport is currently sending data. MUST NOT be {@code null}. 2947 * @param dataManagementIntent An {@link Intent} that can be passed to 2948 * {@link Context#startActivity} in order to launch the transport's data-management UI. It 2949 * may be {@code null} if the transport does not offer any user-facing data 2950 * management UI. 2951 * @param dataManagementLabel A {@link String} to be used as the label for the transport's data 2952 * management affordance. This MUST be {@code null} when dataManagementIntent is 2953 * {@code null} and MUST NOT be {@code null} when dataManagementIntent is not {@code null}. 2954 * @throws SecurityException If the UID of the calling process differs from the package UID of 2955 * {@code transportComponent} or if the caller does NOT have BACKUP permission. 2956 */ 2957 @Override 2958 public void updateTransportAttributes( 2959 ComponentName transportComponent, 2960 String name, 2961 @Nullable Intent configurationIntent, 2962 String currentDestinationString, 2963 @Nullable Intent dataManagementIntent, 2964 @Nullable String dataManagementLabel) { 2965 updateTransportAttributes( 2966 Binder.getCallingUid(), 2967 transportComponent, 2968 name, 2969 configurationIntent, 2970 currentDestinationString, 2971 dataManagementIntent, 2972 dataManagementLabel); 2973 } 2974 2975 @VisibleForTesting 2976 void updateTransportAttributes( 2977 int callingUid, 2978 ComponentName transportComponent, 2979 String name, 2980 @Nullable Intent configurationIntent, 2981 String currentDestinationString, 2982 @Nullable Intent dataManagementIntent, 2983 @Nullable String dataManagementLabel) { 2984 mContext.enforceCallingOrSelfPermission( 2985 android.Manifest.permission.BACKUP, "updateTransportAttributes"); 2986 2987 Preconditions.checkNotNull(transportComponent, "transportComponent can't be null"); 2988 Preconditions.checkNotNull(name, "name can't be null"); 2989 Preconditions.checkNotNull( 2990 currentDestinationString, "currentDestinationString can't be null"); 2991 Preconditions.checkArgument( 2992 (dataManagementIntent == null) == (dataManagementLabel == null), 2993 "dataManagementLabel should be null iff dataManagementIntent is null"); 2994 2995 try { 2996 int transportUid = 2997 mContext.getPackageManager() 2998 .getPackageUid(transportComponent.getPackageName(), 0); 2999 if (callingUid != transportUid) { 3000 throw new SecurityException("Only the transport can change its description"); 3001 } 3002 } catch (NameNotFoundException e) { 3003 throw new SecurityException("Transport package not found", e); 3004 } 3005 3006 final long oldId = Binder.clearCallingIdentity(); 3007 try { 3008 mTransportManager.updateTransportAttributes( 3009 transportComponent, 3010 name, 3011 configurationIntent, 3012 currentDestinationString, 3013 dataManagementIntent, 3014 dataManagementLabel); 3015 } finally { 3016 Binder.restoreCallingIdentity(oldId); 3017 } 3018 } 3019 3020 /** Selects transport {@code transportName} and returns previous selected transport. */ 3021 @Override 3022 @Deprecated 3023 @Nullable 3024 public String selectBackupTransport(String transportName) { 3025 mContext.enforceCallingOrSelfPermission( 3026 android.Manifest.permission.BACKUP, "selectBackupTransport"); 3027 3028 if (!isAllowedByMandatoryBackupTransportPolicy(transportName)) { 3029 // Don't change the transport if it is not allowed. 3030 Slog.w(TAG, "Failed to select transport - disallowed by device owner policy."); 3031 return mTransportManager.getCurrentTransportName(); 3032 } 3033 3034 final long oldId = Binder.clearCallingIdentity(); 3035 try { 3036 String previousTransportName = mTransportManager.selectTransport(transportName); 3037 updateStateForTransport(transportName); 3038 Slog.v(TAG, "selectBackupTransport(transport = " + transportName 3039 + "): previous transport = " + previousTransportName); 3040 return previousTransportName; 3041 } finally { 3042 Binder.restoreCallingIdentity(oldId); 3043 } 3044 } 3045 3046 @Override 3047 public void selectBackupTransportAsync( 3048 ComponentName transportComponent, @Nullable ISelectBackupTransportCallback listener) { 3049 mContext.enforceCallingOrSelfPermission( 3050 android.Manifest.permission.BACKUP, "selectBackupTransportAsync"); 3051 if (!isAllowedByMandatoryBackupTransportPolicy(transportComponent)) { 3052 try { 3053 if (listener != null) { 3054 Slog.w(TAG, "Failed to select transport - disallowed by device owner policy."); 3055 listener.onFailure(BackupManager.ERROR_BACKUP_NOT_ALLOWED); 3056 } 3057 } catch (RemoteException e) { 3058 Slog.e(TAG, "ISelectBackupTransportCallback listener not available"); 3059 } 3060 return; 3061 } 3062 final long oldId = Binder.clearCallingIdentity(); 3063 try { 3064 String transportString = transportComponent.flattenToShortString(); 3065 Slog.v(TAG, "selectBackupTransportAsync(transport = " + transportString + ")"); 3066 mBackupHandler.post( 3067 () -> { 3068 String transportName = null; 3069 int result = 3070 mTransportManager.registerAndSelectTransport(transportComponent); 3071 if (result == BackupManager.SUCCESS) { 3072 try { 3073 transportName = 3074 mTransportManager.getTransportName(transportComponent); 3075 updateStateForTransport(transportName); 3076 } catch (TransportNotRegisteredException e) { 3077 Slog.e(TAG, "Transport got unregistered"); 3078 result = BackupManager.ERROR_TRANSPORT_UNAVAILABLE; 3079 } 3080 } 3081 3082 try { 3083 if (listener != null) { 3084 if (transportName != null) { 3085 listener.onSuccess(transportName); 3086 } else { 3087 listener.onFailure(result); 3088 } 3089 } 3090 } catch (RemoteException e) { 3091 Slog.e(TAG, "ISelectBackupTransportCallback listener not available"); 3092 } 3093 }); 3094 } finally { 3095 Binder.restoreCallingIdentity(oldId); 3096 } 3097 } 3098 3099 /** 3100 * Returns if the specified transport can be set as the current transport without violating the 3101 * mandatory backup transport policy. 3102 */ 3103 private boolean isAllowedByMandatoryBackupTransportPolicy(String transportName) { 3104 ComponentName mandatoryBackupTransport = mBackupPolicyEnforcer.getMandatoryBackupTransport(); 3105 if (mandatoryBackupTransport == null) { 3106 return true; 3107 } 3108 final String mandatoryBackupTransportName; 3109 try { 3110 mandatoryBackupTransportName = 3111 mTransportManager.getTransportName(mandatoryBackupTransport); 3112 } catch (TransportNotRegisteredException e) { 3113 Slog.e(TAG, "mandatory backup transport not registered!"); 3114 return false; 3115 } 3116 return TextUtils.equals(mandatoryBackupTransportName, transportName); 3117 } 3118 3119 /** 3120 * Returns if the specified transport can be set as the current transport without violating the 3121 * mandatory backup transport policy. 3122 */ 3123 private boolean isAllowedByMandatoryBackupTransportPolicy(ComponentName transport) { 3124 ComponentName mandatoryBackupTransport = mBackupPolicyEnforcer.getMandatoryBackupTransport(); 3125 if (mandatoryBackupTransport == null) { 3126 return true; 3127 } 3128 return mandatoryBackupTransport.equals(transport); 3129 } 3130 3131 private void updateStateForTransport(String newTransportName) { 3132 // Publish the name change 3133 Settings.Secure.putString(mContext.getContentResolver(), 3134 Settings.Secure.BACKUP_TRANSPORT, newTransportName); 3135 3136 // And update our current-dataset bookkeeping 3137 String callerLogString = "BMS.updateStateForTransport()"; 3138 TransportClient transportClient = 3139 mTransportManager.getTransportClient(newTransportName, callerLogString); 3140 if (transportClient != null) { 3141 try { 3142 IBackupTransport transport = transportClient.connectOrThrow(callerLogString); 3143 mCurrentToken = transport.getCurrentRestoreSet(); 3144 } catch (Exception e) { 3145 // Oops. We can't know the current dataset token, so reset and figure it out 3146 // when we do the next k/v backup operation on this transport. 3147 mCurrentToken = 0; 3148 Slog.w(TAG, "Transport " + newTransportName + " not available: current token = 0"); 3149 } 3150 mTransportManager.disposeOfTransportClient(transportClient, callerLogString); 3151 } else { 3152 Slog.w(TAG, "Transport " + newTransportName + " not registered: current token = 0"); 3153 // The named transport isn't registered, so we can't know what its current dataset token 3154 // is. Reset as above. 3155 mCurrentToken = 0; 3156 } 3157 } 3158 3159 // Supply the configuration Intent for the given transport. If the name is not one 3160 // of the available transports, or if the transport does not supply any configuration 3161 // UI, the method returns null. 3162 @Override 3163 public Intent getConfigurationIntent(String transportName) { 3164 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, 3165 "getConfigurationIntent"); 3166 try { 3167 Intent intent = mTransportManager.getTransportConfigurationIntent(transportName); 3168 if (MORE_DEBUG) { 3169 Slog.d(TAG, "getConfigurationIntent() returning intent " + intent); 3170 } 3171 return intent; 3172 } catch (TransportNotRegisteredException e) { 3173 Slog.e(TAG, "Unable to get configuration intent from transport: " + e.getMessage()); 3174 return null; 3175 } 3176 } 3177 3178 /** 3179 * Supply the current destination string for the given transport. If the name is not one of the 3180 * registered transports the method will return null. 3181 * 3182 * <p>This string is used VERBATIM as the summary text of the relevant Settings item. 3183 * 3184 * @param transportName The name of the registered transport. 3185 * @return The current destination string or null if the transport is not registered. 3186 */ 3187 @Override 3188 public String getDestinationString(String transportName) { 3189 mContext.enforceCallingOrSelfPermission( 3190 android.Manifest.permission.BACKUP, "getDestinationString"); 3191 3192 try { 3193 String string = mTransportManager.getTransportCurrentDestinationString(transportName); 3194 if (MORE_DEBUG) { 3195 Slog.d(TAG, "getDestinationString() returning " + string); 3196 } 3197 return string; 3198 } catch (TransportNotRegisteredException e) { 3199 Slog.e(TAG, "Unable to get destination string from transport: " + e.getMessage()); 3200 return null; 3201 } 3202 } 3203 3204 // Supply the manage-data intent for the given transport. 3205 @Override 3206 public Intent getDataManagementIntent(String transportName) { 3207 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, 3208 "getDataManagementIntent"); 3209 3210 try { 3211 Intent intent = mTransportManager.getTransportDataManagementIntent(transportName); 3212 if (MORE_DEBUG) { 3213 Slog.d(TAG, "getDataManagementIntent() returning intent " + intent); 3214 } 3215 return intent; 3216 } catch (TransportNotRegisteredException e) { 3217 Slog.e(TAG, "Unable to get management intent from transport: " + e.getMessage()); 3218 return null; 3219 } 3220 } 3221 3222 // Supply the menu label for affordances that fire the manage-data intent 3223 // for the given transport. 3224 @Override 3225 public String getDataManagementLabel(String transportName) { 3226 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, 3227 "getDataManagementLabel"); 3228 3229 try { 3230 String label = mTransportManager.getTransportDataManagementLabel(transportName); 3231 if (MORE_DEBUG) { 3232 Slog.d(TAG, "getDataManagementLabel() returning " + label); 3233 } 3234 return label; 3235 } catch (TransportNotRegisteredException e) { 3236 Slog.e(TAG, "Unable to get management label from transport: " + e.getMessage()); 3237 return null; 3238 } 3239 } 3240 3241 // Callback: a requested backup agent has been instantiated. This should only 3242 // be called from the Activity Manager. 3243 @Override 3244 public void agentConnected(String packageName, IBinder agentBinder) { 3245 synchronized (mAgentConnectLock) { 3246 if (Binder.getCallingUid() == Process.SYSTEM_UID) { 3247 Slog.d(TAG, "agentConnected pkg=" + packageName + " agent=" + agentBinder); 3248 IBackupAgent agent = IBackupAgent.Stub.asInterface(agentBinder); 3249 mConnectedAgent = agent; 3250 mConnecting = false; 3251 } else { 3252 Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid() 3253 + " claiming agent connected"); 3254 } 3255 mAgentConnectLock.notifyAll(); 3256 } 3257 } 3258 3259 // Callback: a backup agent has failed to come up, or has unexpectedly quit. 3260 // If the agent failed to come up in the first place, the agentBinder argument 3261 // will be null. This should only be called from the Activity Manager. 3262 @Override 3263 public void agentDisconnected(String packageName) { 3264 // TODO: handle backup being interrupted 3265 synchronized (mAgentConnectLock) { 3266 if (Binder.getCallingUid() == Process.SYSTEM_UID) { 3267 mConnectedAgent = null; 3268 mConnecting = false; 3269 } else { 3270 Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid() 3271 + " claiming agent disconnected"); 3272 } 3273 mAgentConnectLock.notifyAll(); 3274 } 3275 } 3276 3277 // An application being installed will need a restore pass, then the Package Manager 3278 // will need to be told when the restore is finished. 3279 @Override 3280 public void restoreAtInstall(String packageName, int token) { 3281 if (Binder.getCallingUid() != Process.SYSTEM_UID) { 3282 Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid() 3283 + " attemping install-time restore"); 3284 return; 3285 } 3286 3287 boolean skip = false; 3288 3289 long restoreSet = getAvailableRestoreToken(packageName); 3290 if (DEBUG) { 3291 Slog.v(TAG, "restoreAtInstall pkg=" + packageName 3292 + " token=" + Integer.toHexString(token) 3293 + " restoreSet=" + Long.toHexString(restoreSet)); 3294 } 3295 if (restoreSet == 0) { 3296 if (MORE_DEBUG) Slog.i(TAG, "No restore set"); 3297 skip = true; 3298 } 3299 3300 TransportClient transportClient = 3301 mTransportManager.getCurrentTransportClient("BMS.restoreAtInstall()"); 3302 if (transportClient == null) { 3303 if (DEBUG) Slog.w(TAG, "No transport client"); 3304 skip = true; 3305 } 3306 3307 if (!mAutoRestore) { 3308 if (DEBUG) { 3309 Slog.w(TAG, "Non-restorable state: auto=" + mAutoRestore); 3310 } 3311 skip = true; 3312 } 3313 3314 if (!skip) { 3315 try { 3316 // okay, we're going to attempt a restore of this package from this restore set. 3317 // The eventual message back into the Package Manager to run the post-install 3318 // steps for 'token' will be issued from the restore handling code. 3319 3320 mWakelock.acquire(); 3321 3322 OnTaskFinishedListener listener = caller -> { 3323 mTransportManager.disposeOfTransportClient(transportClient, caller); 3324 mWakelock.release(); 3325 }; 3326 3327 if (MORE_DEBUG) { 3328 Slog.d(TAG, "Restore at install of " + packageName); 3329 } 3330 Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE); 3331 msg.obj = 3332 RestoreParams.createForRestoreAtInstall( 3333 transportClient, 3334 /* observer */ null, 3335 /* monitor */ null, 3336 restoreSet, 3337 packageName, 3338 token, 3339 listener); 3340 mBackupHandler.sendMessage(msg); 3341 } catch (Exception e) { 3342 // Calling into the transport broke; back off and proceed with the installation. 3343 Slog.e(TAG, "Unable to contact transport: " + e.getMessage()); 3344 skip = true; 3345 } 3346 } 3347 3348 if (skip) { 3349 // Auto-restore disabled or no way to attempt a restore 3350 3351 if (transportClient != null) { 3352 mTransportManager.disposeOfTransportClient( 3353 transportClient, "BMS.restoreAtInstall()"); 3354 } 3355 3356 // Tell the PackageManager to proceed with the post-install handling for this package. 3357 if (DEBUG) Slog.v(TAG, "Finishing install immediately"); 3358 try { 3359 mPackageManagerBinder.finishPackageInstall(token, false); 3360 } catch (RemoteException e) { /* can't happen */ } 3361 } 3362 } 3363 3364 // Hand off a restore session 3365 @Override 3366 public IRestoreSession beginRestoreSession(String packageName, String transport) { 3367 if (DEBUG) { 3368 Slog.v(TAG, "beginRestoreSession: pkg=" + packageName 3369 + " transport=" + transport); 3370 } 3371 3372 boolean needPermission = true; 3373 if (transport == null) { 3374 transport = mTransportManager.getCurrentTransportName(); 3375 3376 if (packageName != null) { 3377 PackageInfo app = null; 3378 try { 3379 app = mPackageManager.getPackageInfo(packageName, 0); 3380 } catch (NameNotFoundException nnf) { 3381 Slog.w(TAG, "Asked to restore nonexistent pkg " + packageName); 3382 throw new IllegalArgumentException("Package " + packageName + " not found"); 3383 } 3384 3385 if (app.applicationInfo.uid == Binder.getCallingUid()) { 3386 // So: using the current active transport, and the caller has asked 3387 // that its own package will be restored. In this narrow use case 3388 // we do not require the caller to hold the permission. 3389 needPermission = false; 3390 } 3391 } 3392 } 3393 3394 if (needPermission) { 3395 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, 3396 "beginRestoreSession"); 3397 } else { 3398 if (DEBUG) Slog.d(TAG, "restoring self on current transport; no permission needed"); 3399 } 3400 3401 synchronized (this) { 3402 if (mActiveRestoreSession != null) { 3403 Slog.i(TAG, "Restore session requested but one already active"); 3404 return null; 3405 } 3406 if (mBackupRunning) { 3407 Slog.i(TAG, "Restore session requested but currently running backups"); 3408 return null; 3409 } 3410 mActiveRestoreSession = new ActiveRestoreSession(this, packageName, transport); 3411 mBackupHandler.sendEmptyMessageDelayed(MSG_RESTORE_SESSION_TIMEOUT, 3412 mAgentTimeoutParameters.getRestoreAgentTimeoutMillis()); 3413 } 3414 return mActiveRestoreSession; 3415 } 3416 3417 public void clearRestoreSession(ActiveRestoreSession currentSession) { 3418 synchronized (this) { 3419 if (currentSession != mActiveRestoreSession) { 3420 Slog.e(TAG, "ending non-current restore session"); 3421 } else { 3422 if (DEBUG) Slog.v(TAG, "Clearing restore session and halting timeout"); 3423 mActiveRestoreSession = null; 3424 mBackupHandler.removeMessages(MSG_RESTORE_SESSION_TIMEOUT); 3425 } 3426 } 3427 } 3428 3429 // Note that a currently-active backup agent has notified us that it has 3430 // completed the given outstanding asynchronous backup/restore operation. 3431 @Override 3432 public void opComplete(int token, long result) { 3433 if (MORE_DEBUG) { 3434 Slog.v(TAG, "opComplete: " + Integer.toHexString(token) + " result=" + result); 3435 } 3436 Operation op = null; 3437 synchronized (mCurrentOpLock) { 3438 op = mCurrentOperations.get(token); 3439 if (op != null) { 3440 if (op.state == OP_TIMEOUT) { 3441 // The operation already timed out, and this is a late response. Tidy up 3442 // and ignore it; we've already dealt with the timeout. 3443 op = null; 3444 mCurrentOperations.delete(token); 3445 } else if (op.state == OP_ACKNOWLEDGED) { 3446 if (DEBUG) { 3447 Slog.w(TAG, "Received duplicate ack for token=" + 3448 Integer.toHexString(token)); 3449 } 3450 op = null; 3451 mCurrentOperations.remove(token); 3452 } else if (op.state == OP_PENDING) { 3453 // Can't delete op from mCurrentOperations. waitUntilOperationComplete can be 3454 // called after we we receive this call. 3455 op.state = OP_ACKNOWLEDGED; 3456 } 3457 } 3458 mCurrentOpLock.notifyAll(); 3459 } 3460 3461 // The completion callback, if any, is invoked on the handler 3462 if (op != null && op.callback != null) { 3463 Pair<BackupRestoreTask, Long> callbackAndResult = Pair.create(op.callback, result); 3464 Message msg = mBackupHandler.obtainMessage(MSG_OP_COMPLETE, callbackAndResult); 3465 mBackupHandler.sendMessage(msg); 3466 } 3467 } 3468 3469 @Override 3470 public boolean isAppEligibleForBackup(String packageName) { 3471 mContext.enforceCallingOrSelfPermission( 3472 android.Manifest.permission.BACKUP, "isAppEligibleForBackup"); 3473 3474 long oldToken = Binder.clearCallingIdentity(); 3475 try { 3476 String callerLogString = "BMS.isAppEligibleForBackup"; 3477 TransportClient transportClient = 3478 mTransportManager.getCurrentTransportClient(callerLogString); 3479 boolean eligible = 3480 AppBackupUtils.appIsRunningAndEligibleForBackupWithTransport( 3481 transportClient, packageName, mPackageManager); 3482 if (transportClient != null) { 3483 mTransportManager.disposeOfTransportClient(transportClient, callerLogString); 3484 } 3485 return eligible; 3486 } finally { 3487 Binder.restoreCallingIdentity(oldToken); 3488 } 3489 } 3490 3491 @Override 3492 public String[] filterAppsEligibleForBackup(String[] packages) { 3493 mContext.enforceCallingOrSelfPermission( 3494 android.Manifest.permission.BACKUP, "filterAppsEligibleForBackup"); 3495 3496 long oldToken = Binder.clearCallingIdentity(); 3497 try { 3498 String callerLogString = "BMS.filterAppsEligibleForBackup"; 3499 TransportClient transportClient = 3500 mTransportManager.getCurrentTransportClient(callerLogString); 3501 List<String> eligibleApps = new LinkedList<>(); 3502 for (String packageName : packages) { 3503 if (AppBackupUtils 3504 .appIsRunningAndEligibleForBackupWithTransport( 3505 transportClient, packageName, mPackageManager)) { 3506 eligibleApps.add(packageName); 3507 } 3508 } 3509 if (transportClient != null) { 3510 mTransportManager.disposeOfTransportClient(transportClient, callerLogString); 3511 } 3512 return eligibleApps.toArray(new String[eligibleApps.size()]); 3513 } finally { 3514 Binder.restoreCallingIdentity(oldToken); 3515 } 3516 } 3517 3518 @Override 3519 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 3520 if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return; 3521 3522 long identityToken = Binder.clearCallingIdentity(); 3523 try { 3524 if (args != null) { 3525 for (String arg : args) { 3526 if ("-h".equals(arg)) { 3527 pw.println("'dumpsys backup' optional arguments:"); 3528 pw.println(" -h : this help text"); 3529 pw.println(" a[gents] : dump information about defined backup agents"); 3530 return; 3531 } else if ("agents".startsWith(arg)) { 3532 dumpAgents(pw); 3533 return; 3534 } else if ("transportclients".equals(arg.toLowerCase())) { 3535 mTransportManager.dumpTransportClients(pw); 3536 return; 3537 } else if ("transportstats".equals(arg.toLowerCase())) { 3538 mTransportManager.dumpTransportStats(pw); 3539 return; 3540 } 3541 } 3542 } 3543 dumpInternal(pw); 3544 } finally { 3545 Binder.restoreCallingIdentity(identityToken); 3546 } 3547 } 3548 3549 private void dumpAgents(PrintWriter pw) { 3550 List<PackageInfo> agentPackages = allAgentPackages(); 3551 pw.println("Defined backup agents:"); 3552 for (PackageInfo pkg : agentPackages) { 3553 pw.print(" "); 3554 pw.print(pkg.packageName); 3555 pw.println(':'); 3556 pw.print(" "); 3557 pw.println(pkg.applicationInfo.backupAgentName); 3558 } 3559 } 3560 3561 private void dumpInternal(PrintWriter pw) { 3562 synchronized (mQueueLock) { 3563 pw.println("Backup Manager is " + (mEnabled ? "enabled" : "disabled") 3564 + " / " + (!mProvisioned ? "not " : "") + "provisioned / " 3565 + (this.mPendingInits.size() == 0 ? "not " : "") + "pending init"); 3566 pw.println("Auto-restore is " + (mAutoRestore ? "enabled" : "disabled")); 3567 if (mBackupRunning) pw.println("Backup currently running"); 3568 pw.println(isBackupOperationInProgress() ? "Backup in progress" : "No backups running"); 3569 pw.println("Last backup pass started: " + mLastBackupPass 3570 + " (now = " + System.currentTimeMillis() + ')'); 3571 pw.println(" next scheduled: " + KeyValueBackupJob.nextScheduled()); 3572 3573 pw.println("Transport whitelist:"); 3574 for (ComponentName transport : mTransportManager.getTransportWhitelist()) { 3575 pw.print(" "); 3576 pw.println(transport.flattenToShortString()); 3577 } 3578 3579 pw.println("Available transports:"); 3580 final String[] transports = listAllTransports(); 3581 if (transports != null) { 3582 for (String t : transports) { 3583 pw.println((t.equals(mTransportManager.getCurrentTransportName()) ? " * " 3584 : " ") + t); 3585 try { 3586 File dir = new File(mBaseStateDir, 3587 mTransportManager.getTransportDirName(t)); 3588 pw.println(" destination: " 3589 + mTransportManager.getTransportCurrentDestinationString(t)); 3590 pw.println(" intent: " 3591 + mTransportManager.getTransportConfigurationIntent(t)); 3592 for (File f : dir.listFiles()) { 3593 pw.println( 3594 " " + f.getName() + " - " + f.length() + " state bytes"); 3595 } 3596 } catch (Exception e) { 3597 Slog.e(TAG, "Error in transport", e); 3598 pw.println(" Error: " + e); 3599 } 3600 } 3601 } 3602 3603 mTransportManager.dumpTransportClients(pw); 3604 3605 pw.println("Pending init: " + mPendingInits.size()); 3606 for (String s : mPendingInits) { 3607 pw.println(" " + s); 3608 } 3609 3610 if (DEBUG_BACKUP_TRACE) { 3611 synchronized (mBackupTrace) { 3612 if (!mBackupTrace.isEmpty()) { 3613 pw.println("Most recent backup trace:"); 3614 for (String s : mBackupTrace) { 3615 pw.println(" " + s); 3616 } 3617 } 3618 } 3619 } 3620 3621 pw.print("Ancestral: "); 3622 pw.println(Long.toHexString(mAncestralToken)); 3623 pw.print("Current: "); 3624 pw.println(Long.toHexString(mCurrentToken)); 3625 3626 int N = mBackupParticipants.size(); 3627 pw.println("Participants:"); 3628 for (int i = 0; i < N; i++) { 3629 int uid = mBackupParticipants.keyAt(i); 3630 pw.print(" uid: "); 3631 pw.println(uid); 3632 HashSet<String> participants = mBackupParticipants.valueAt(i); 3633 for (String app : participants) { 3634 pw.println(" " + app); 3635 } 3636 } 3637 3638 pw.println("Ancestral packages: " 3639 + (mAncestralPackages == null ? "none" : mAncestralPackages.size())); 3640 if (mAncestralPackages != null) { 3641 for (String pkg : mAncestralPackages) { 3642 pw.println(" " + pkg); 3643 } 3644 } 3645 3646 Set<String> processedPackages = mProcessedPackagesJournal.getPackagesCopy(); 3647 pw.println("Ever backed up: " + processedPackages.size()); 3648 for (String pkg : processedPackages) { 3649 pw.println(" " + pkg); 3650 } 3651 3652 pw.println("Pending key/value backup: " + mPendingBackups.size()); 3653 for (BackupRequest req : mPendingBackups.values()) { 3654 pw.println(" " + req); 3655 } 3656 3657 pw.println("Full backup queue:" + mFullBackupQueue.size()); 3658 for (FullBackupEntry entry : mFullBackupQueue) { 3659 pw.print(" "); 3660 pw.print(entry.lastBackup); 3661 pw.print(" : "); 3662 pw.println(entry.packageName); 3663 } 3664 } 3665 } 3666 3667 3668 @Override 3669 public IBackupManager getBackupManagerBinder() { 3670 return mBackupManagerBinder; 3671 } 3672 3673 } 3674