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