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