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.fullbackup; 18 19 import static com.android.server.backup.BackupManagerService.DEBUG; 20 import static com.android.server.backup.BackupManagerService.DEBUG_SCHEDULING; 21 import static com.android.server.backup.BackupManagerService.MORE_DEBUG; 22 23 import android.annotation.Nullable; 24 import android.app.IBackupAgent; 25 import android.app.backup.BackupManager; 26 import android.app.backup.BackupManagerMonitor; 27 import android.app.backup.BackupProgress; 28 import android.app.backup.BackupTransport; 29 import android.app.backup.IBackupManagerMonitor; 30 import android.app.backup.IBackupObserver; 31 import android.app.backup.IFullBackupRestoreObserver; 32 import android.content.pm.PackageInfo; 33 import android.content.pm.PackageManager; 34 import android.content.pm.PackageManager.NameNotFoundException; 35 import android.os.ParcelFileDescriptor; 36 import android.os.RemoteException; 37 import android.util.EventLog; 38 import android.util.Log; 39 import android.util.Slog; 40 41 import com.android.server.EventLogTags; 42 import com.android.server.backup.BackupAgentTimeoutParameters; 43 import com.android.server.backup.BackupRestoreTask; 44 import com.android.server.backup.FullBackupJob; 45 import com.android.server.backup.OperationStorage; 46 import com.android.server.backup.OperationStorage.OpState; 47 import com.android.server.backup.OperationStorage.OpType; 48 import com.android.server.backup.TransportManager; 49 import com.android.server.backup.UserBackupManagerService; 50 import com.android.server.backup.internal.OnTaskFinishedListener; 51 import com.android.server.backup.remote.RemoteCall; 52 import com.android.server.backup.transport.BackupTransportClient; 53 import com.android.server.backup.transport.TransportConnection; 54 import com.android.server.backup.transport.TransportNotAvailableException; 55 import com.android.server.backup.utils.BackupEligibilityRules; 56 import com.android.server.backup.utils.BackupManagerMonitorUtils; 57 import com.android.server.backup.utils.BackupObserverUtils; 58 59 import com.google.android.collect.Sets; 60 61 import java.io.FileInputStream; 62 import java.io.FileOutputStream; 63 import java.io.IOException; 64 import java.util.ArrayList; 65 import java.util.List; 66 import java.util.Objects; 67 import java.util.Set; 68 import java.util.concurrent.CountDownLatch; 69 import java.util.concurrent.TimeUnit; 70 import java.util.concurrent.atomic.AtomicLong; 71 72 /** 73 * Full backup task extension used for transport-oriented operation. 74 * 75 * Flow: 76 * For each requested package: 77 * - Spin off a new SinglePackageBackupRunner (mBackupRunner) for the current package. 78 * - Wait until preflight is complete. (mBackupRunner.getPreflightResultBlocking()) 79 * - If preflight data size is within limit, start reading data from agent pipe and writing 80 * to transport pipe. While there is data to send, call transport.sendBackupData(int) to 81 * tell the transport how many bytes to expect on its pipe. 82 * - After sending all data, call transport.finishBackup() if things went well. And 83 * transport.cancelFullBackup() otherwise. 84 * 85 * Interactions with mCurrentOperations: 86 * - An entry for this object is added to mCurrentOperations for the entire lifetime of this 87 * object. Used to cancel the operation. 88 * - SinglePackageBackupRunner and SinglePackageBackupPreflight will put ephemeral entries 89 * to get timeouts or operation complete callbacks. 90 * 91 * Handling cancels: 92 * - The contract we provide is that the task won't interact with the transport after 93 * handleCancel() is done executing. 94 * - This task blocks at 3 points: 1. Preflight result check 2. Reading on agent side pipe 95 * and 3. Get backup result from mBackupRunner. 96 * - Bubbling up handleCancel to mBackupRunner handles all 3: 1. Calls handleCancel on the 97 * preflight operation which counts down on the preflight latch. 2. Tears down the agent, 98 * so read() returns -1. 3. Notifies mCurrentOpLock which unblocks 99 * mBackupRunner.getBackupResultBlocking(). 100 */ 101 public class PerformFullTransportBackupTask extends FullBackupTask implements BackupRestoreTask { 102 /** 103 * @throws IllegalStateException if there's no transport available. 104 */ newWithCurrentTransport( UserBackupManagerService backupManagerService, OperationStorage operationStorage, IFullBackupRestoreObserver observer, String[] whichPackages, boolean updateSchedule, FullBackupJob runningJob, CountDownLatch latch, IBackupObserver backupObserver, IBackupManagerMonitor monitor, boolean userInitiated, String caller, BackupEligibilityRules backupEligibilityRules)105 public static PerformFullTransportBackupTask newWithCurrentTransport( 106 UserBackupManagerService backupManagerService, 107 OperationStorage operationStorage, 108 IFullBackupRestoreObserver observer, 109 String[] whichPackages, 110 boolean updateSchedule, 111 FullBackupJob runningJob, 112 CountDownLatch latch, 113 IBackupObserver backupObserver, 114 IBackupManagerMonitor monitor, 115 boolean userInitiated, 116 String caller, 117 BackupEligibilityRules backupEligibilityRules) { 118 TransportManager transportManager = backupManagerService.getTransportManager(); 119 TransportConnection transportConnection = transportManager.getCurrentTransportClient( 120 caller); 121 if (transportConnection == null) { 122 throw new IllegalStateException("No TransportConnection available"); 123 } 124 OnTaskFinishedListener listener = 125 listenerCaller -> 126 transportManager.disposeOfTransportClient(transportConnection, 127 listenerCaller); 128 return new PerformFullTransportBackupTask( 129 backupManagerService, 130 operationStorage, 131 transportConnection, 132 observer, 133 whichPackages, 134 updateSchedule, 135 runningJob, 136 latch, 137 backupObserver, 138 monitor, 139 listener, 140 userInitiated, 141 backupEligibilityRules); 142 } 143 144 private static final String TAG = "PFTBT"; 145 146 private UserBackupManagerService mUserBackupManagerService; 147 private final Object mCancelLock = new Object(); 148 149 OperationStorage mOperationStorage; 150 List<PackageInfo> mPackages; 151 PackageInfo mCurrentPackage; 152 boolean mUpdateSchedule; 153 CountDownLatch mLatch; 154 FullBackupJob mJob; // if a scheduled job needs to be finished afterwards 155 IBackupObserver mBackupObserver; 156 @Nullable private IBackupManagerMonitor mMonitor; 157 boolean mUserInitiated; 158 SinglePackageBackupRunner mBackupRunner; 159 private final int mBackupRunnerOpToken; 160 private final OnTaskFinishedListener mListener; 161 private final TransportConnection mTransportConnection; 162 private final int mUserId; 163 164 // This is true when a backup operation for some package is in progress. 165 private volatile boolean mIsDoingBackup; 166 private volatile boolean mCancelAll; 167 private final int mCurrentOpToken; 168 private final BackupAgentTimeoutParameters mAgentTimeoutParameters; 169 private final BackupEligibilityRules mBackupEligibilityRules; 170 PerformFullTransportBackupTask(UserBackupManagerService backupManagerService, OperationStorage operationStorage, TransportConnection transportConnection, IFullBackupRestoreObserver observer, String[] whichPackages, boolean updateSchedule, FullBackupJob runningJob, CountDownLatch latch, IBackupObserver backupObserver, @Nullable IBackupManagerMonitor monitor, @Nullable OnTaskFinishedListener listener, boolean userInitiated, BackupEligibilityRules backupEligibilityRules)171 public PerformFullTransportBackupTask(UserBackupManagerService backupManagerService, 172 OperationStorage operationStorage, 173 TransportConnection transportConnection, 174 IFullBackupRestoreObserver observer, 175 String[] whichPackages, boolean updateSchedule, 176 FullBackupJob runningJob, CountDownLatch latch, IBackupObserver backupObserver, 177 @Nullable IBackupManagerMonitor monitor, @Nullable OnTaskFinishedListener listener, 178 boolean userInitiated, BackupEligibilityRules backupEligibilityRules) { 179 super(observer); 180 mUserBackupManagerService = backupManagerService; 181 mOperationStorage = operationStorage; 182 mTransportConnection = transportConnection; 183 mUpdateSchedule = updateSchedule; 184 mLatch = latch; 185 mJob = runningJob; 186 mPackages = new ArrayList<>(whichPackages.length); 187 mBackupObserver = backupObserver; 188 mMonitor = monitor; 189 mListener = (listener != null) ? listener : OnTaskFinishedListener.NOP; 190 mUserInitiated = userInitiated; 191 mCurrentOpToken = backupManagerService.generateRandomIntegerToken(); 192 mBackupRunnerOpToken = backupManagerService.generateRandomIntegerToken(); 193 mAgentTimeoutParameters = Objects.requireNonNull( 194 backupManagerService.getAgentTimeoutParameters(), 195 "Timeout parameters cannot be null"); 196 mUserId = backupManagerService.getUserId(); 197 mBackupEligibilityRules = backupEligibilityRules; 198 199 if (backupManagerService.isBackupOperationInProgress()) { 200 if (DEBUG) { 201 Slog.d(TAG, "Skipping full backup. A backup is already in progress."); 202 } 203 mCancelAll = true; 204 return; 205 } 206 207 for (String pkg : whichPackages) { 208 try { 209 PackageManager pm = backupManagerService.getPackageManager(); 210 PackageInfo info = pm.getPackageInfoAsUser(pkg, 211 PackageManager.GET_SIGNING_CERTIFICATES, mUserId); 212 mCurrentPackage = info; 213 if (!mBackupEligibilityRules.appIsEligibleForBackup(info.applicationInfo)) { 214 // Cull any packages that have indicated that backups are not permitted, 215 // that run as system-domain uids but do not define their own backup agents, 216 // as well as any explicit mention of the 'special' shared-storage agent 217 // package (we handle that one at the end). 218 if (MORE_DEBUG) { 219 Slog.d(TAG, "Ignoring ineligible package " + pkg); 220 } 221 mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor, 222 BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_INELIGIBLE, 223 mCurrentPackage, 224 BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, 225 null); 226 BackupObserverUtils.sendBackupOnPackageResult(mBackupObserver, pkg, 227 BackupManager.ERROR_BACKUP_NOT_ALLOWED); 228 continue; 229 } else if (!mBackupEligibilityRules.appGetsFullBackup(info)) { 230 // Cull any packages that are found in the queue but now aren't supposed 231 // to get full-data backup operations. 232 if (MORE_DEBUG) { 233 Slog.d(TAG, "Ignoring full-data backup of key/value participant " 234 + pkg); 235 } 236 mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor, 237 BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_KEY_VALUE_PARTICIPANT, 238 mCurrentPackage, 239 BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, 240 null); 241 BackupObserverUtils.sendBackupOnPackageResult(mBackupObserver, pkg, 242 BackupManager.ERROR_BACKUP_NOT_ALLOWED); 243 continue; 244 } else if (mBackupEligibilityRules.appIsStopped(info.applicationInfo)) { 245 // Cull any packages in the 'stopped' state: they've either just been 246 // installed or have explicitly been force-stopped by the user. In both 247 // cases we do not want to launch them for backup. 248 if (MORE_DEBUG) { 249 Slog.d(TAG, "Ignoring stopped package " + pkg); 250 } 251 mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor, 252 BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_STOPPED, 253 mCurrentPackage, 254 BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, 255 null); 256 BackupObserverUtils.sendBackupOnPackageResult(mBackupObserver, pkg, 257 BackupManager.ERROR_BACKUP_NOT_ALLOWED); 258 continue; 259 } 260 mPackages.add(info); 261 } catch (NameNotFoundException e) { 262 Slog.i(TAG, "Requested package " + pkg + " not found; ignoring"); 263 mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor, 264 BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_NOT_FOUND, 265 mCurrentPackage, 266 BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, 267 null); 268 } 269 } 270 271 mPackages = backupManagerService.filterUserFacingPackages(mPackages); 272 273 Set<String> packageNames = Sets.newHashSet(); 274 for (PackageInfo pkgInfo : mPackages) { 275 packageNames.add(pkgInfo.packageName); 276 } 277 278 Slog.d(TAG, "backupmanager pftbt token=" + Integer.toHexString(mCurrentOpToken)); 279 mOperationStorage.registerOperationForPackages(mCurrentOpToken, OpState.PENDING, 280 packageNames, this, OpType.BACKUP); 281 } 282 283 // public, because called from KeyValueBackupTask.finishTask. unregisterTask()284 public void unregisterTask() { 285 mOperationStorage.removeOperation(mCurrentOpToken); 286 } 287 288 @Override execute()289 public void execute() { 290 // Nothing to do. 291 } 292 293 @Override handleCancel(boolean cancelAll)294 public void handleCancel(boolean cancelAll) { 295 synchronized (mCancelLock) { 296 // We only support 'cancelAll = true' case for this task. Cancelling of a single package 297 298 // due to timeout is handled by SinglePackageBackupRunner and 299 // SinglePackageBackupPreflight. 300 301 if (!cancelAll) { 302 Slog.wtf(TAG, "Expected cancelAll to be true."); 303 } 304 305 if (mCancelAll) { 306 Slog.d(TAG, "Ignoring duplicate cancel call."); 307 return; 308 } 309 310 mCancelAll = true; 311 if (mIsDoingBackup) { 312 mUserBackupManagerService.handleCancel(mBackupRunnerOpToken, cancelAll); 313 try { 314 // If we're running a backup we should be connected to a transport 315 BackupTransportClient transport = 316 mTransportConnection.getConnectedTransport("PFTBT.handleCancel()"); 317 transport.cancelFullBackup(); 318 } catch (RemoteException | TransportNotAvailableException e) { 319 Slog.w(TAG, "Error calling cancelFullBackup() on transport: " + e); 320 // Can't do much. 321 } 322 } 323 } 324 } 325 326 @Override operationComplete(long result)327 public void operationComplete(long result) { 328 // Nothing to do. 329 } 330 331 @Override run()332 public void run() { 333 334 // data from the app, passed to us for bridging to the transport 335 ParcelFileDescriptor[] enginePipes = null; 336 337 // Pipe through which we write data to the transport 338 ParcelFileDescriptor[] transportPipes = null; 339 340 long backoff = 0; 341 int backupRunStatus = BackupManager.SUCCESS; 342 343 try { 344 if (!mUserBackupManagerService.isEnabled() 345 || !mUserBackupManagerService.isSetupComplete()) { 346 // Backups are globally disabled, so don't proceed. 347 if (DEBUG) { 348 Slog.i(TAG, "full backup requested but enabled=" + mUserBackupManagerService 349 .isEnabled() 350 + " setupComplete=" + mUserBackupManagerService.isSetupComplete() 351 + "; ignoring"); 352 } 353 int monitoringEvent; 354 if (mUserBackupManagerService.isSetupComplete()) { 355 monitoringEvent = BackupManagerMonitor.LOG_EVENT_ID_BACKUP_DISABLED; 356 } else { 357 monitoringEvent = BackupManagerMonitor.LOG_EVENT_ID_DEVICE_NOT_PROVISIONED; 358 } 359 mMonitor = BackupManagerMonitorUtils 360 .monitorEvent(mMonitor, monitoringEvent, null, 361 BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, 362 null); 363 mUpdateSchedule = false; 364 backupRunStatus = BackupManager.ERROR_BACKUP_NOT_ALLOWED; 365 return; 366 } 367 368 BackupTransportClient transport = mTransportConnection.connect("PFTBT.run()"); 369 if (transport == null) { 370 Slog.w(TAG, "Transport not present; full data backup not performed"); 371 backupRunStatus = BackupManager.ERROR_TRANSPORT_ABORTED; 372 mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor, 373 BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_TRANSPORT_NOT_PRESENT, 374 mCurrentPackage, BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT, 375 null); 376 return; 377 } 378 379 // Set up to send data to the transport 380 final int N = mPackages.size(); 381 final byte[] buffer = new byte[8192]; 382 for (int i = 0; i < N; i++) { 383 mBackupRunner = null; 384 PackageInfo currentPackage = mPackages.get(i); 385 String packageName = currentPackage.packageName; 386 if (DEBUG) { 387 Slog.i(TAG, "Initiating full-data transport backup of " + packageName 388 + " token: " + mCurrentOpToken); 389 } 390 EventLog.writeEvent(EventLogTags.FULL_BACKUP_PACKAGE, packageName); 391 392 transportPipes = ParcelFileDescriptor.createPipe(); 393 394 // Tell the transport the data's coming 395 int flags = mUserInitiated ? BackupTransport.FLAG_USER_INITIATED : 0; 396 int backupPackageStatus; 397 long quota = Long.MAX_VALUE; 398 synchronized (mCancelLock) { 399 if (mCancelAll) { 400 break; 401 } 402 backupPackageStatus = transport.performFullBackup(currentPackage, 403 transportPipes[0], flags); 404 405 if (backupPackageStatus == BackupTransport.TRANSPORT_OK) { 406 quota = transport.getBackupQuota(currentPackage.packageName, 407 true /* isFullBackup */); 408 // Now set up the backup engine / data source end of things 409 enginePipes = ParcelFileDescriptor.createPipe(); 410 mBackupRunner = 411 new SinglePackageBackupRunner(enginePipes[1], currentPackage, 412 mTransportConnection, quota, mBackupRunnerOpToken, 413 transport.getTransportFlags()); 414 // The runner dup'd the pipe half, so we close it here 415 enginePipes[1].close(); 416 enginePipes[1] = null; 417 418 mIsDoingBackup = true; 419 } 420 } 421 if (backupPackageStatus == BackupTransport.TRANSPORT_OK) { 422 423 // The transport has its own copy of the read end of the pipe, 424 // so close ours now 425 transportPipes[0].close(); 426 transportPipes[0] = null; 427 428 // Spin off the runner to fetch the app's data and pipe it 429 // into the engine pipes 430 (new Thread(mBackupRunner, "package-backup-bridge")).start(); 431 432 // Read data off the engine pipe and pass it to the transport 433 // pipe until we hit EOD on the input stream. We do not take 434 // close() responsibility for these FDs into these stream wrappers. 435 FileInputStream in = new FileInputStream( 436 enginePipes[0].getFileDescriptor()); 437 FileOutputStream out = new FileOutputStream( 438 transportPipes[1].getFileDescriptor()); 439 long totalRead = 0; 440 final long preflightResult = mBackupRunner.getPreflightResultBlocking(); 441 // Preflight result is negative if some error happened on preflight. 442 if (preflightResult < 0) { 443 if (MORE_DEBUG) { 444 Slog.d(TAG, "Backup error after preflight of package " 445 + packageName + ": " + preflightResult 446 + ", not running backup."); 447 } 448 mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor, 449 BackupManagerMonitor.LOG_EVENT_ID_ERROR_PREFLIGHT, 450 mCurrentPackage, 451 BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, 452 BackupManagerMonitorUtils.putMonitoringExtra(null, 453 BackupManagerMonitor.EXTRA_LOG_PREFLIGHT_ERROR, 454 preflightResult)); 455 backupPackageStatus = (int) preflightResult; 456 } else { 457 int nRead = 0; 458 do { 459 nRead = in.read(buffer); 460 if (MORE_DEBUG) { 461 Slog.v(TAG, "in.read(buffer) from app: " + nRead); 462 } 463 if (nRead > 0) { 464 out.write(buffer, 0, nRead); 465 synchronized (mCancelLock) { 466 if (!mCancelAll) { 467 backupPackageStatus = transport.sendBackupData(nRead); 468 } 469 } 470 totalRead += nRead; 471 if (mBackupObserver != null && preflightResult > 0) { 472 BackupObserverUtils 473 .sendBackupOnUpdate(mBackupObserver, packageName, 474 new BackupProgress(preflightResult, totalRead)); 475 } 476 } 477 } while (nRead > 0 478 && backupPackageStatus == BackupTransport.TRANSPORT_OK); 479 // Despite preflight succeeded, package still can hit quota on flight. 480 if (backupPackageStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) { 481 Slog.w(TAG, "Package hit quota limit in-flight " + packageName 482 + ": " + totalRead + " of " + quota); 483 mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor, 484 BackupManagerMonitor.LOG_EVENT_ID_QUOTA_HIT_PREFLIGHT, 485 mCurrentPackage, 486 BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT, 487 null); 488 mBackupRunner.sendQuotaExceeded(totalRead, quota); 489 } 490 } 491 492 final int backupRunnerResult = mBackupRunner.getBackupResultBlocking(); 493 494 synchronized (mCancelLock) { 495 mIsDoingBackup = false; 496 // If mCancelCurrent is true, we have already called cancelFullBackup(). 497 if (!mCancelAll) { 498 if (backupRunnerResult == BackupTransport.TRANSPORT_OK) { 499 // If we were otherwise in a good state, now interpret the final 500 // result based on what finishBackup() returns. If we're in a 501 // failure case already, preserve that result and ignore whatever 502 // finishBackup() reports. 503 final int finishResult = transport.finishBackup(); 504 if (backupPackageStatus == BackupTransport.TRANSPORT_OK) { 505 backupPackageStatus = finishResult; 506 } 507 } else { 508 transport.cancelFullBackup(); 509 } 510 } 511 } 512 513 // A transport-originated error here means that we've hit an error that the 514 // runner doesn't know about, so it's still moving data but we're pulling the 515 // rug out from under it. Don't ask for its result: we already know better 516 // and we'll hang if we block waiting for it, since it relies on us to 517 // read back the data it's writing into the engine. Just proceed with 518 // a graceful failure. The runner/engine mechanism will tear itself 519 // down cleanly when we close the pipes from this end. Transport-level 520 // errors take precedence over agent/app-specific errors for purposes of 521 // determining our course of action. 522 if (backupPackageStatus == BackupTransport.TRANSPORT_OK) { 523 // We still could fail in backup runner thread. 524 if (backupRunnerResult != BackupTransport.TRANSPORT_OK) { 525 // If there was an error in runner thread and 526 // not TRANSPORT_ERROR here, overwrite it. 527 backupPackageStatus = backupRunnerResult; 528 } 529 } else { 530 if (MORE_DEBUG) { 531 Slog.i(TAG, "Transport-level failure; cancelling agent work"); 532 } 533 } 534 535 if (MORE_DEBUG) { 536 Slog.i(TAG, "Done delivering backup data: result=" 537 + backupPackageStatus); 538 } 539 540 if (backupPackageStatus != BackupTransport.TRANSPORT_OK) { 541 Slog.w(TAG, "Error " + backupPackageStatus + " backing up " 542 + packageName); 543 } 544 545 // Also ask the transport how long it wants us to wait before 546 // moving on to the next package, if any. 547 backoff = transport.requestFullBackupTime(); 548 if (DEBUG_SCHEDULING) { 549 Slog.i(TAG, "Transport suggested backoff=" + backoff); 550 } 551 552 } 553 554 // Roll this package to the end of the backup queue if we're 555 // in a queue-driven mode (regardless of success/failure) 556 if (mUpdateSchedule) { 557 mUserBackupManagerService.enqueueFullBackup( 558 packageName, System.currentTimeMillis()); 559 } 560 561 if (backupPackageStatus == BackupTransport.TRANSPORT_PACKAGE_REJECTED) { 562 BackupObserverUtils 563 .sendBackupOnPackageResult(mBackupObserver, packageName, 564 BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED); 565 if (DEBUG) { 566 Slog.i(TAG, "Transport rejected backup of " + packageName 567 + ", skipping"); 568 } 569 EventLog.writeEvent(EventLogTags.FULL_BACKUP_AGENT_FAILURE, packageName, 570 "transport rejected"); 571 // This failure state can come either a-priori from the transport, or 572 // from the preflight pass. If we got as far as preflight, we now need 573 // to tear down the target process. 574 if (mBackupRunner != null) { 575 mUserBackupManagerService.tearDownAgentAndKill( 576 currentPackage.applicationInfo); 577 } 578 // ... and continue looping. 579 } else if (backupPackageStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) { 580 BackupObserverUtils 581 .sendBackupOnPackageResult(mBackupObserver, packageName, 582 BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED); 583 if (DEBUG) { 584 Slog.i(TAG, "Transport quota exceeded for package: " + packageName); 585 EventLog.writeEvent(EventLogTags.FULL_BACKUP_QUOTA_EXCEEDED, 586 packageName); 587 } 588 mUserBackupManagerService.tearDownAgentAndKill(currentPackage.applicationInfo); 589 // Do nothing, clean up, and continue looping. 590 } else if (backupPackageStatus == BackupTransport.AGENT_ERROR) { 591 BackupObserverUtils 592 .sendBackupOnPackageResult(mBackupObserver, packageName, 593 BackupManager.ERROR_AGENT_FAILURE); 594 Slog.w(TAG, "Application failure for package: " + packageName); 595 EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName); 596 mUserBackupManagerService.tearDownAgentAndKill(currentPackage.applicationInfo); 597 // Do nothing, clean up, and continue looping. 598 } else if (backupPackageStatus == BackupManager.ERROR_BACKUP_CANCELLED) { 599 BackupObserverUtils 600 .sendBackupOnPackageResult(mBackupObserver, packageName, 601 BackupManager.ERROR_BACKUP_CANCELLED); 602 Slog.w(TAG, "Backup cancelled. package=" + packageName + 603 ", cancelAll=" + mCancelAll); 604 EventLog.writeEvent(EventLogTags.FULL_BACKUP_CANCELLED, packageName); 605 mUserBackupManagerService.tearDownAgentAndKill(currentPackage.applicationInfo); 606 // Do nothing, clean up, and continue looping. 607 } else if (backupPackageStatus != BackupTransport.TRANSPORT_OK) { 608 BackupObserverUtils 609 .sendBackupOnPackageResult(mBackupObserver, packageName, 610 BackupManager.ERROR_TRANSPORT_ABORTED); 611 Slog.w(TAG, "Transport failed; aborting backup: " + backupPackageStatus); 612 EventLog.writeEvent(EventLogTags.FULL_BACKUP_TRANSPORT_FAILURE); 613 // Abort entire backup pass. 614 backupRunStatus = BackupManager.ERROR_TRANSPORT_ABORTED; 615 mUserBackupManagerService.tearDownAgentAndKill(currentPackage.applicationInfo); 616 return; 617 } else { 618 // Success! 619 BackupObserverUtils 620 .sendBackupOnPackageResult(mBackupObserver, packageName, 621 BackupManager.SUCCESS); 622 EventLog.writeEvent(EventLogTags.FULL_BACKUP_SUCCESS, packageName); 623 mUserBackupManagerService.logBackupComplete(packageName); 624 } 625 cleanUpPipes(transportPipes); 626 cleanUpPipes(enginePipes); 627 if (currentPackage.applicationInfo != null) { 628 Slog.i(TAG, "Unbinding agent in " + packageName); 629 try { 630 mUserBackupManagerService.getActivityManager().unbindBackupAgent( 631 currentPackage.applicationInfo); 632 } catch (RemoteException e) { /* can't happen; activity manager is local */ } 633 } 634 } 635 } catch (Exception e) { 636 backupRunStatus = BackupManager.ERROR_TRANSPORT_ABORTED; 637 Slog.w(TAG, "Exception trying full transport backup", e); 638 mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor, 639 BackupManagerMonitor.LOG_EVENT_ID_EXCEPTION_FULL_BACKUP, 640 mCurrentPackage, 641 BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, 642 BackupManagerMonitorUtils.putMonitoringExtra(null, 643 BackupManagerMonitor.EXTRA_LOG_EXCEPTION_FULL_BACKUP, 644 Log.getStackTraceString(e))); 645 646 } finally { 647 648 if (mCancelAll) { 649 backupRunStatus = BackupManager.ERROR_BACKUP_CANCELLED; 650 } 651 652 if (DEBUG) { 653 Slog.i(TAG, "Full backup completed with status: " + backupRunStatus); 654 } 655 BackupObserverUtils.sendBackupFinished(mBackupObserver, backupRunStatus); 656 657 cleanUpPipes(transportPipes); 658 cleanUpPipes(enginePipes); 659 660 unregisterTask(); 661 662 if (mJob != null) { 663 mJob.finishBackupPass(mUserId); 664 } 665 666 synchronized (mUserBackupManagerService.getQueueLock()) { 667 mUserBackupManagerService.setRunningFullBackupTask(null); 668 } 669 670 mListener.onFinished("PFTBT.run()"); 671 672 mLatch.countDown(); 673 674 // Now that we're actually done with schedule-driven work, reschedule 675 // the next pass based on the new queue state. 676 if (mUpdateSchedule) { 677 mUserBackupManagerService.scheduleNextFullBackupJob(backoff); 678 } 679 680 Slog.i(TAG, "Full data backup pass finished."); 681 mUserBackupManagerService.getWakelock().release(); 682 } 683 } 684 cleanUpPipes(ParcelFileDescriptor[] pipes)685 void cleanUpPipes(ParcelFileDescriptor[] pipes) { 686 if (pipes != null) { 687 if (pipes[0] != null) { 688 ParcelFileDescriptor fd = pipes[0]; 689 pipes[0] = null; 690 try { 691 fd.close(); 692 } catch (IOException e) { 693 Slog.w(TAG, "Unable to close pipe!"); 694 } 695 } 696 if (pipes[1] != null) { 697 ParcelFileDescriptor fd = pipes[1]; 698 pipes[1] = null; 699 try { 700 fd.close(); 701 } catch (IOException e) { 702 Slog.w(TAG, "Unable to close pipe!"); 703 } 704 } 705 } 706 } 707 708 // Run the backup and pipe it back to the given socket -- expects to run on 709 // a standalone thread. The runner owns this half of the pipe, and closes 710 // it to indicate EOD to the other end. 711 class SinglePackageBackupPreflight implements BackupRestoreTask, FullBackupPreflight { 712 final AtomicLong mResult = new AtomicLong(BackupTransport.AGENT_ERROR); 713 final CountDownLatch mLatch = new CountDownLatch(1); 714 final TransportConnection mTransportConnection; 715 final long mQuota; 716 private final int mCurrentOpToken; 717 private final int mTransportFlags; 718 SinglePackageBackupPreflight( TransportConnection transportConnection, long quota, int currentOpToken, int transportFlags)719 SinglePackageBackupPreflight( 720 TransportConnection transportConnection, 721 long quota, 722 int currentOpToken, 723 int transportFlags) { 724 mTransportConnection = transportConnection; 725 mQuota = quota; 726 mCurrentOpToken = currentOpToken; 727 mTransportFlags = transportFlags; 728 } 729 730 @Override preflightFullBackup(PackageInfo pkg, IBackupAgent agent)731 public int preflightFullBackup(PackageInfo pkg, IBackupAgent agent) { 732 int result; 733 long fullBackupAgentTimeoutMillis = 734 mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis(); 735 try { 736 mUserBackupManagerService.prepareOperationTimeout( 737 mCurrentOpToken, fullBackupAgentTimeoutMillis, this, OpType.BACKUP_WAIT); 738 if (MORE_DEBUG) { 739 Slog.d(TAG, "Preflighting full payload of " + pkg.packageName); 740 } 741 agent.doMeasureFullBackup(mQuota, mCurrentOpToken, 742 mUserBackupManagerService.getBackupManagerBinder(), mTransportFlags); 743 744 // Now wait to get our result back. If this backstop timeout is reached without 745 // the latch being thrown, flow will continue as though a result or "normal" 746 // timeout had been produced. In case of a real backstop timeout, mResult 747 // will still contain the value it was constructed with, AGENT_ERROR, which 748 // intentionaly falls into the "just report failure" code. 749 mLatch.await(fullBackupAgentTimeoutMillis, TimeUnit.MILLISECONDS); 750 751 long totalSize = mResult.get(); 752 // If preflight timed out, mResult will contain error code as int. 753 if (totalSize < 0) { 754 return (int) totalSize; 755 } 756 if (MORE_DEBUG) { 757 Slog.v(TAG, "Got preflight response; size=" + totalSize); 758 } 759 760 BackupTransportClient transport = 761 mTransportConnection.connectOrThrow("PFTBT$SPBP.preflightFullBackup()"); 762 result = transport.checkFullBackupSize(totalSize); 763 if (result == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) { 764 if (MORE_DEBUG) { 765 Slog.d(TAG, "Package hit quota limit on preflight " + 766 pkg.packageName + ": " + totalSize + " of " + mQuota); 767 } 768 RemoteCall.execute( 769 callback -> agent.doQuotaExceeded(totalSize, mQuota, callback), 770 mAgentTimeoutParameters.getQuotaExceededTimeoutMillis()); 771 } 772 } catch (Exception e) { 773 Slog.w(TAG, "Exception preflighting " + pkg.packageName + ": " + e.getMessage()); 774 result = BackupTransport.AGENT_ERROR; 775 } 776 return result; 777 } 778 779 @Override execute()780 public void execute() { 781 // Unused. 782 } 783 784 @Override operationComplete(long result)785 public void operationComplete(long result) { 786 // got the callback, and our preflightFullBackup() method is waiting for the result 787 if (MORE_DEBUG) { 788 Slog.i(TAG, "Preflight op complete, result=" + result); 789 } 790 mResult.set(result); 791 mLatch.countDown(); 792 mOperationStorage.removeOperation(mCurrentOpToken); 793 } 794 795 @Override handleCancel(boolean cancelAll)796 public void handleCancel(boolean cancelAll) { 797 if (MORE_DEBUG) { 798 Slog.i(TAG, "Preflight cancelled; failing"); 799 } 800 mResult.set(BackupTransport.AGENT_ERROR); 801 mLatch.countDown(); 802 mOperationStorage.removeOperation(mCurrentOpToken); 803 } 804 805 @Override getExpectedSizeOrErrorCode()806 public long getExpectedSizeOrErrorCode() { 807 long fullBackupAgentTimeoutMillis = 808 mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis(); 809 try { 810 mLatch.await(fullBackupAgentTimeoutMillis, TimeUnit.MILLISECONDS); 811 return mResult.get(); 812 } catch (InterruptedException e) { 813 return BackupTransport.NO_MORE_DATA; 814 } 815 } 816 } 817 818 class SinglePackageBackupRunner implements Runnable, BackupRestoreTask { 819 final ParcelFileDescriptor mOutput; 820 final PackageInfo mTarget; 821 final SinglePackageBackupPreflight mPreflight; 822 final CountDownLatch mPreflightLatch; 823 final CountDownLatch mBackupLatch; 824 private final int mCurrentOpToken; 825 private final int mEphemeralToken; 826 private FullBackupEngine mEngine; 827 private volatile int mPreflightResult; 828 private volatile int mBackupResult; 829 private final long mQuota; 830 private volatile boolean mIsCancelled; 831 private final int mTransportFlags; 832 SinglePackageBackupRunner(ParcelFileDescriptor output, PackageInfo target, TransportConnection transportConnection, long quota, int currentOpToken, int transportFlags)833 SinglePackageBackupRunner(ParcelFileDescriptor output, PackageInfo target, 834 TransportConnection transportConnection, long quota, int currentOpToken, 835 int transportFlags) throws IOException { 836 mOutput = ParcelFileDescriptor.dup(output.getFileDescriptor()); 837 mTarget = target; 838 mCurrentOpToken = currentOpToken; 839 mEphemeralToken = mUserBackupManagerService.generateRandomIntegerToken(); 840 mPreflight = new SinglePackageBackupPreflight( 841 transportConnection, quota, mEphemeralToken, transportFlags); 842 mPreflightLatch = new CountDownLatch(1); 843 mBackupLatch = new CountDownLatch(1); 844 mPreflightResult = BackupTransport.AGENT_ERROR; 845 mBackupResult = BackupTransport.AGENT_ERROR; 846 mQuota = quota; 847 mTransportFlags = transportFlags; 848 registerTask(target.packageName); 849 } 850 registerTask(String packageName)851 void registerTask(String packageName) { 852 Set<String> packages = Sets.newHashSet(packageName); 853 mOperationStorage.registerOperationForPackages(mCurrentOpToken, OpState.PENDING, 854 packages, this, OpType.BACKUP_WAIT); 855 } 856 unregisterTask()857 void unregisterTask() { 858 mOperationStorage.removeOperation(mCurrentOpToken); 859 } 860 861 @Override run()862 public void run() { 863 FileOutputStream out = new FileOutputStream(mOutput.getFileDescriptor()); 864 mEngine = 865 new FullBackupEngine( 866 mUserBackupManagerService, 867 out, 868 mPreflight, 869 mTarget, 870 false, 871 this, 872 mQuota, 873 mCurrentOpToken, 874 mTransportFlags, 875 mBackupEligibilityRules); 876 try { 877 try { 878 if (!mIsCancelled) { 879 mPreflightResult = mEngine.preflightCheck(); 880 } 881 } finally { 882 mPreflightLatch.countDown(); 883 } 884 // If there is no error on preflight, continue backup. 885 if (mPreflightResult == BackupTransport.TRANSPORT_OK) { 886 if (!mIsCancelled) { 887 mBackupResult = mEngine.backupOnePackage(); 888 } 889 } 890 } catch (Exception e) { 891 Slog.w(TAG, "Exception during full package backup of " + mTarget.packageName, 892 e); 893 } finally { 894 unregisterTask(); 895 mBackupLatch.countDown(); 896 try { 897 mOutput.close(); 898 } catch (IOException e) { 899 Slog.w(TAG, "Error closing transport pipe in runner"); 900 } 901 } 902 } 903 sendQuotaExceeded(final long backupDataBytes, final long quotaBytes)904 public void sendQuotaExceeded(final long backupDataBytes, final long quotaBytes) { 905 mEngine.sendQuotaExceeded(backupDataBytes, quotaBytes); 906 } 907 908 // If preflight succeeded, returns positive number - preflight size, 909 // otherwise return negative error code. getPreflightResultBlocking()910 long getPreflightResultBlocking() { 911 long fullBackupAgentTimeoutMillis = 912 mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis(); 913 try { 914 mPreflightLatch.await(fullBackupAgentTimeoutMillis, TimeUnit.MILLISECONDS); 915 if (mIsCancelled) { 916 return BackupManager.ERROR_BACKUP_CANCELLED; 917 } 918 if (mPreflightResult == BackupTransport.TRANSPORT_OK) { 919 return mPreflight.getExpectedSizeOrErrorCode(); 920 } else { 921 return mPreflightResult; 922 } 923 } catch (InterruptedException e) { 924 return BackupTransport.AGENT_ERROR; 925 } 926 } 927 getBackupResultBlocking()928 int getBackupResultBlocking() { 929 long fullBackupAgentTimeoutMillis = 930 mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis(); 931 try { 932 mBackupLatch.await(fullBackupAgentTimeoutMillis, TimeUnit.MILLISECONDS); 933 if (mIsCancelled) { 934 return BackupManager.ERROR_BACKUP_CANCELLED; 935 } 936 return mBackupResult; 937 } catch (InterruptedException e) { 938 return BackupTransport.AGENT_ERROR; 939 } 940 } 941 942 943 // BackupRestoreTask interface: specifically, timeout detection 944 945 @Override execute()946 public void execute() { /* intentionally empty */ } 947 948 @Override operationComplete(long result)949 public void operationComplete(long result) { /* intentionally empty */ } 950 951 @Override handleCancel(boolean cancelAll)952 public void handleCancel(boolean cancelAll) { 953 if (DEBUG) { 954 Slog.w(TAG, "Full backup cancel of " + mTarget.packageName); 955 } 956 957 mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor, 958 BackupManagerMonitor.LOG_EVENT_ID_FULL_BACKUP_CANCEL, 959 mCurrentPackage, BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT, null); 960 mIsCancelled = true; 961 // Cancel tasks spun off by this task. 962 mUserBackupManagerService.handleCancel(mEphemeralToken, cancelAll); 963 mUserBackupManagerService.tearDownAgentAndKill(mTarget.applicationInfo); 964 // Free up everyone waiting on this task and its children. 965 mPreflightLatch.countDown(); 966 mBackupLatch.countDown(); 967 // We are done with this operation. 968 mOperationStorage.removeOperation(mCurrentOpToken); 969 } 970 } 971 } 972