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