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