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