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.Flags; 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 int chunkSizeInBytes = 8 * 1024; // 8KB 394 if (Flags.enableMaxSizeWritesToPipes()) { 395 // Linux pipe capacity (buffer size) is 16 pages where each page is 4KB 396 chunkSizeInBytes = 64 * 1024; // 64KB 397 } 398 final byte[] buffer = new byte[chunkSizeInBytes]; 399 for (int i = 0; i < N; i++) { 400 mBackupRunner = null; 401 PackageInfo currentPackage = mPackages.get(i); 402 String packageName = currentPackage.packageName; 403 if (DEBUG) { 404 Slog.i(TAG, "Initiating full-data transport backup of " + packageName 405 + " token: " + mCurrentOpToken); 406 } 407 EventLog.writeEvent(EventLogTags.FULL_BACKUP_PACKAGE, packageName); 408 409 transportPipes = ParcelFileDescriptor.createPipe(); 410 411 // Tell the transport the data's coming 412 int flags = mUserInitiated ? BackupTransport.FLAG_USER_INITIATED : 0; 413 int backupPackageStatus; 414 long quota = Long.MAX_VALUE; 415 synchronized (mCancelLock) { 416 if (mCancelAll) { 417 break; 418 } 419 backupPackageStatus = transport.performFullBackup(currentPackage, 420 transportPipes[0], flags); 421 422 if (backupPackageStatus == BackupTransport.TRANSPORT_OK) { 423 quota = transport.getBackupQuota(currentPackage.packageName, 424 true /* isFullBackup */); 425 // Now set up the backup engine / data source end of things 426 enginePipes = ParcelFileDescriptor.createPipe(); 427 mBackupRunner = 428 new SinglePackageBackupRunner(enginePipes[1], currentPackage, 429 mTransportConnection, quota, mBackupRunnerOpToken, 430 transport.getTransportFlags()); 431 // The runner dup'd the pipe half, so we close it here 432 enginePipes[1].close(); 433 enginePipes[1] = null; 434 435 mIsDoingBackup = true; 436 } 437 } 438 if (backupPackageStatus == BackupTransport.TRANSPORT_OK) { 439 440 // The transport has its own copy of the read end of the pipe, 441 // so close ours now 442 transportPipes[0].close(); 443 transportPipes[0] = null; 444 445 // Spin off the runner to fetch the app's data and pipe it 446 // into the engine pipes 447 (new Thread(mBackupRunner, "package-backup-bridge")).start(); 448 449 // Read data off the engine pipe and pass it to the transport 450 // pipe until we hit EOD on the input stream. We do not take 451 // close() responsibility for these FDs into these stream wrappers. 452 FileInputStream in = new FileInputStream( 453 enginePipes[0].getFileDescriptor()); 454 FileOutputStream out = new FileOutputStream( 455 transportPipes[1].getFileDescriptor()); 456 long totalRead = 0; 457 final long preflightResult = mBackupRunner.getPreflightResultBlocking(); 458 // Preflight result is negative if some error happened on preflight. 459 if (preflightResult < 0) { 460 if (MORE_DEBUG) { 461 Slog.d(TAG, "Backup error after preflight of package " 462 + packageName + ": " + preflightResult 463 + ", not running backup."); 464 } 465 mBackupManagerMonitorEventSender.monitorEvent( 466 BackupManagerMonitor.LOG_EVENT_ID_ERROR_PREFLIGHT, 467 mCurrentPackage, 468 BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, 469 mBackupManagerMonitorEventSender.putMonitoringExtra(null, 470 BackupManagerMonitor.EXTRA_LOG_PREFLIGHT_ERROR, 471 preflightResult)); 472 backupPackageStatus = (int) preflightResult; 473 } else { 474 int nRead = 0; 475 do { 476 nRead = in.read(buffer); 477 if (MORE_DEBUG) { 478 Slog.v(TAG, "in.read(buffer) from app: " + nRead); 479 } 480 if (nRead > 0) { 481 out.write(buffer, 0, nRead); 482 synchronized (mCancelLock) { 483 if (!mCancelAll) { 484 backupPackageStatus = transport.sendBackupData(nRead); 485 } 486 } 487 totalRead += nRead; 488 if (mBackupObserver != null && preflightResult > 0) { 489 BackupObserverUtils 490 .sendBackupOnUpdate(mBackupObserver, packageName, 491 new BackupProgress(preflightResult, totalRead)); 492 } 493 } 494 } while (nRead > 0 495 && backupPackageStatus == BackupTransport.TRANSPORT_OK); 496 // Despite preflight succeeded, package still can hit quota on flight. 497 if (backupPackageStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) { 498 Slog.w(TAG, "Package hit quota limit in-flight " + packageName 499 + ": " + totalRead + " of " + quota); 500 mBackupManagerMonitorEventSender.monitorEvent( 501 BackupManagerMonitor.LOG_EVENT_ID_QUOTA_HIT_PREFLIGHT, 502 mCurrentPackage, 503 BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT, 504 null); 505 mBackupRunner.sendQuotaExceeded(totalRead, quota); 506 } 507 } 508 509 final int backupRunnerResult = mBackupRunner.getBackupResultBlocking(); 510 511 synchronized (mCancelLock) { 512 mIsDoingBackup = false; 513 // If mCancelCurrent is true, we have already called cancelFullBackup(). 514 if (!mCancelAll) { 515 if (backupRunnerResult == BackupTransport.TRANSPORT_OK) { 516 // If we were otherwise in a good state, now interpret the final 517 // result based on what finishBackup() returns. If we're in a 518 // failure case already, preserve that result and ignore whatever 519 // finishBackup() reports. 520 final int finishResult = transport.finishBackup(); 521 if (backupPackageStatus == BackupTransport.TRANSPORT_OK) { 522 backupPackageStatus = finishResult; 523 } 524 } else { 525 transport.cancelFullBackup(); 526 } 527 } 528 } 529 530 // A transport-originated error here means that we've hit an error that the 531 // runner doesn't know about, so it's still moving data but we're pulling the 532 // rug out from under it. Don't ask for its result: we already know better 533 // and we'll hang if we block waiting for it, since it relies on us to 534 // read back the data it's writing into the engine. Just proceed with 535 // a graceful failure. The runner/engine mechanism will tear itself 536 // down cleanly when we close the pipes from this end. Transport-level 537 // errors take precedence over agent/app-specific errors for purposes of 538 // determining our course of action. 539 if (backupPackageStatus == BackupTransport.TRANSPORT_OK) { 540 // We still could fail in backup runner thread. 541 if (backupRunnerResult != BackupTransport.TRANSPORT_OK) { 542 // If there was an error in runner thread and 543 // not TRANSPORT_ERROR here, overwrite it. 544 backupPackageStatus = backupRunnerResult; 545 } 546 } else { 547 if (MORE_DEBUG) { 548 Slog.i(TAG, "Transport-level failure; cancelling agent work"); 549 } 550 } 551 552 if (MORE_DEBUG) { 553 Slog.i(TAG, "Done delivering backup data: result=" 554 + backupPackageStatus); 555 } 556 557 if (backupPackageStatus != BackupTransport.TRANSPORT_OK) { 558 Slog.w(TAG, "Error " + backupPackageStatus + " backing up " 559 + packageName); 560 } 561 562 // Also ask the transport how long it wants us to wait before 563 // moving on to the next package, if any. 564 backoff = transport.requestFullBackupTime(); 565 if (DEBUG_SCHEDULING) { 566 Slog.i(TAG, "Transport suggested backoff=" + backoff); 567 } 568 569 } 570 571 // Roll this package to the end of the backup queue if we're 572 // in a queue-driven mode (regardless of success/failure) 573 if (mUpdateSchedule) { 574 mUserBackupManagerService.enqueueFullBackup( 575 packageName, System.currentTimeMillis()); 576 } 577 578 if (backupPackageStatus == BackupTransport.TRANSPORT_PACKAGE_REJECTED) { 579 BackupObserverUtils 580 .sendBackupOnPackageResult(mBackupObserver, packageName, 581 BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED); 582 if (DEBUG) { 583 Slog.i(TAG, "Transport rejected backup of " + packageName 584 + ", skipping"); 585 } 586 EventLog.writeEvent(EventLogTags.FULL_BACKUP_AGENT_FAILURE, packageName, 587 "transport rejected"); 588 // This failure state can come either a-priori from the transport, or 589 // from the preflight pass. If we got as far as preflight, we now need 590 // to tear down the target process. 591 if (mBackupRunner != null) { 592 mUserBackupManagerService.tearDownAgentAndKill( 593 currentPackage.applicationInfo); 594 } 595 // ... and continue looping. 596 } else if (backupPackageStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) { 597 BackupObserverUtils 598 .sendBackupOnPackageResult(mBackupObserver, packageName, 599 BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED); 600 if (DEBUG) { 601 Slog.i(TAG, "Transport quota exceeded for package: " + packageName); 602 EventLog.writeEvent(EventLogTags.FULL_BACKUP_QUOTA_EXCEEDED, 603 packageName); 604 } 605 mUserBackupManagerService.tearDownAgentAndKill(currentPackage.applicationInfo); 606 // Do nothing, clean up, and continue looping. 607 } else if (backupPackageStatus == BackupTransport.AGENT_ERROR) { 608 BackupObserverUtils 609 .sendBackupOnPackageResult(mBackupObserver, packageName, 610 BackupManager.ERROR_AGENT_FAILURE); 611 Slog.w(TAG, "Application failure for package: " + packageName); 612 EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName); 613 mUserBackupManagerService.tearDownAgentAndKill(currentPackage.applicationInfo); 614 // Do nothing, clean up, and continue looping. 615 } else if (backupPackageStatus == BackupManager.ERROR_BACKUP_CANCELLED) { 616 BackupObserverUtils 617 .sendBackupOnPackageResult(mBackupObserver, packageName, 618 BackupManager.ERROR_BACKUP_CANCELLED); 619 Slog.w(TAG, "Backup cancelled. package=" + packageName + 620 ", cancelAll=" + mCancelAll); 621 EventLog.writeEvent(EventLogTags.FULL_BACKUP_CANCELLED, packageName); 622 mUserBackupManagerService.tearDownAgentAndKill(currentPackage.applicationInfo); 623 // Do nothing, clean up, and continue looping. 624 } else if (backupPackageStatus != BackupTransport.TRANSPORT_OK) { 625 BackupObserverUtils 626 .sendBackupOnPackageResult(mBackupObserver, packageName, 627 BackupManager.ERROR_TRANSPORT_ABORTED); 628 Slog.w(TAG, "Transport failed; aborting backup: " + backupPackageStatus); 629 EventLog.writeEvent(EventLogTags.FULL_BACKUP_TRANSPORT_FAILURE); 630 // Abort entire backup pass. 631 backupRunStatus = BackupManager.ERROR_TRANSPORT_ABORTED; 632 mUserBackupManagerService.tearDownAgentAndKill(currentPackage.applicationInfo); 633 return; 634 } else { 635 // Success! 636 BackupObserverUtils 637 .sendBackupOnPackageResult(mBackupObserver, packageName, 638 BackupManager.SUCCESS); 639 EventLog.writeEvent(EventLogTags.FULL_BACKUP_SUCCESS, packageName); 640 mUserBackupManagerService.logBackupComplete(packageName); 641 } 642 cleanUpPipes(transportPipes); 643 cleanUpPipes(enginePipes); 644 if (currentPackage.applicationInfo != null) { 645 Slog.i(TAG, "Unbinding agent in " + packageName); 646 try { 647 mUserBackupManagerService.getActivityManager().unbindBackupAgent( 648 currentPackage.applicationInfo); 649 } catch (RemoteException e) { /* can't happen; activity manager is local */ } 650 } 651 } 652 } catch (Exception e) { 653 backupRunStatus = BackupManager.ERROR_TRANSPORT_ABORTED; 654 Slog.w(TAG, "Exception trying full transport backup", e); 655 mBackupManagerMonitorEventSender.monitorEvent( 656 BackupManagerMonitor.LOG_EVENT_ID_EXCEPTION_FULL_BACKUP, 657 mCurrentPackage, 658 BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, 659 mBackupManagerMonitorEventSender.putMonitoringExtra(null, 660 BackupManagerMonitor.EXTRA_LOG_EXCEPTION_FULL_BACKUP, 661 Log.getStackTraceString(e))); 662 663 } finally { 664 665 if (mCancelAll) { 666 backupRunStatus = BackupManager.ERROR_BACKUP_CANCELLED; 667 } 668 669 if (DEBUG) { 670 Slog.i(TAG, "Full backup completed with status: " + backupRunStatus); 671 } 672 BackupObserverUtils.sendBackupFinished(mBackupObserver, backupRunStatus); 673 674 cleanUpPipes(transportPipes); 675 cleanUpPipes(enginePipes); 676 677 unregisterTask(); 678 679 if (mJob != null) { 680 mJob.finishBackupPass(mUserId); 681 } 682 683 synchronized (mUserBackupManagerService.getQueueLock()) { 684 mUserBackupManagerService.setRunningFullBackupTask(null); 685 } 686 687 mListener.onFinished("PFTBT.run()"); 688 689 mLatch.countDown(); 690 691 // Now that we're actually done with schedule-driven work, reschedule 692 // the next pass based on the new queue state. 693 if (mUpdateSchedule) { 694 mUserBackupManagerService.scheduleNextFullBackupJob(backoff); 695 } 696 697 Slog.i(TAG, "Full data backup pass finished."); 698 mUserBackupManagerService.getWakelock().release(); 699 } 700 } 701 cleanUpPipes(ParcelFileDescriptor[] pipes)702 void cleanUpPipes(ParcelFileDescriptor[] pipes) { 703 if (pipes != null) { 704 if (pipes[0] != null) { 705 ParcelFileDescriptor fd = pipes[0]; 706 pipes[0] = null; 707 try { 708 fd.close(); 709 } catch (IOException e) { 710 Slog.w(TAG, "Unable to close pipe!"); 711 } 712 } 713 if (pipes[1] != null) { 714 ParcelFileDescriptor fd = pipes[1]; 715 pipes[1] = null; 716 try { 717 fd.close(); 718 } catch (IOException e) { 719 Slog.w(TAG, "Unable to close pipe!"); 720 } 721 } 722 } 723 } 724 725 // Run the backup and pipe it back to the given socket -- expects to run on 726 // a standalone thread. The runner owns this half of the pipe, and closes 727 // it to indicate EOD to the other end. 728 class SinglePackageBackupPreflight implements BackupRestoreTask, FullBackupPreflight { 729 final AtomicLong mResult = new AtomicLong(BackupTransport.AGENT_ERROR); 730 final CountDownLatch mLatch = new CountDownLatch(1); 731 final TransportConnection mTransportConnection; 732 final long mQuota; 733 private final int mCurrentOpToken; 734 private final int mTransportFlags; 735 SinglePackageBackupPreflight( TransportConnection transportConnection, long quota, int currentOpToken, int transportFlags)736 SinglePackageBackupPreflight( 737 TransportConnection transportConnection, 738 long quota, 739 int currentOpToken, 740 int transportFlags) { 741 mTransportConnection = transportConnection; 742 mQuota = quota; 743 mCurrentOpToken = currentOpToken; 744 mTransportFlags = transportFlags; 745 } 746 747 @Override preflightFullBackup(PackageInfo pkg, IBackupAgent agent)748 public int preflightFullBackup(PackageInfo pkg, IBackupAgent agent) { 749 int result; 750 long fullBackupAgentTimeoutMillis = 751 mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis(); 752 try { 753 mUserBackupManagerService.prepareOperationTimeout( 754 mCurrentOpToken, fullBackupAgentTimeoutMillis, this, OpType.BACKUP_WAIT); 755 if (MORE_DEBUG) { 756 Slog.d(TAG, "Preflighting full payload of " + pkg.packageName); 757 } 758 agent.doMeasureFullBackup(mQuota, mCurrentOpToken, 759 mUserBackupManagerService.getBackupManagerBinder(), mTransportFlags); 760 761 // Now wait to get our result back. If this backstop timeout is reached without 762 // the latch being thrown, flow will continue as though a result or "normal" 763 // timeout had been produced. In case of a real backstop timeout, mResult 764 // will still contain the value it was constructed with, AGENT_ERROR, which 765 // intentionaly falls into the "just report failure" code. 766 mLatch.await(fullBackupAgentTimeoutMillis, TimeUnit.MILLISECONDS); 767 768 long totalSize = mResult.get(); 769 // If preflight timed out, mResult will contain error code as int. 770 if (totalSize < 0) { 771 return (int) totalSize; 772 } 773 if (MORE_DEBUG) { 774 Slog.v(TAG, "Got preflight response; size=" + totalSize); 775 } 776 777 BackupTransportClient transport = 778 mTransportConnection.connectOrThrow("PFTBT$SPBP.preflightFullBackup()"); 779 result = transport.checkFullBackupSize(totalSize); 780 if (result == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) { 781 if (MORE_DEBUG) { 782 Slog.d(TAG, "Package hit quota limit on preflight " + 783 pkg.packageName + ": " + totalSize + " of " + mQuota); 784 } 785 RemoteCall.execute( 786 callback -> agent.doQuotaExceeded(totalSize, mQuota, callback), 787 mAgentTimeoutParameters.getQuotaExceededTimeoutMillis()); 788 } 789 } catch (Exception e) { 790 Slog.w(TAG, "Exception preflighting " + pkg.packageName + ": " + e.getMessage()); 791 result = BackupTransport.AGENT_ERROR; 792 } 793 return result; 794 } 795 796 @Override execute()797 public void execute() { 798 // Unused. 799 } 800 801 @Override operationComplete(long result)802 public void operationComplete(long result) { 803 // got the callback, and our preflightFullBackup() method is waiting for the result 804 if (MORE_DEBUG) { 805 Slog.i(TAG, "Preflight op complete, result=" + result); 806 } 807 mResult.set(result); 808 mLatch.countDown(); 809 mOperationStorage.removeOperation(mCurrentOpToken); 810 } 811 812 @Override handleCancel(boolean cancelAll)813 public void handleCancel(boolean cancelAll) { 814 if (MORE_DEBUG) { 815 Slog.i(TAG, "Preflight cancelled; failing"); 816 } 817 mResult.set(BackupTransport.AGENT_ERROR); 818 mLatch.countDown(); 819 mOperationStorage.removeOperation(mCurrentOpToken); 820 } 821 822 @Override getExpectedSizeOrErrorCode()823 public long getExpectedSizeOrErrorCode() { 824 long fullBackupAgentTimeoutMillis = 825 mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis(); 826 try { 827 mLatch.await(fullBackupAgentTimeoutMillis, TimeUnit.MILLISECONDS); 828 return mResult.get(); 829 } catch (InterruptedException e) { 830 return BackupTransport.NO_MORE_DATA; 831 } 832 } 833 } 834 835 class SinglePackageBackupRunner implements Runnable, BackupRestoreTask { 836 final ParcelFileDescriptor mOutput; 837 final PackageInfo mTarget; 838 final SinglePackageBackupPreflight mPreflight; 839 final CountDownLatch mPreflightLatch; 840 final CountDownLatch mBackupLatch; 841 private final int mCurrentOpToken; 842 private final int mEphemeralToken; 843 private FullBackupEngine mEngine; 844 private volatile int mPreflightResult; 845 private volatile int mBackupResult; 846 private final long mQuota; 847 private volatile boolean mIsCancelled; 848 private final int mTransportFlags; 849 SinglePackageBackupRunner(ParcelFileDescriptor output, PackageInfo target, TransportConnection transportConnection, long quota, int currentOpToken, int transportFlags)850 SinglePackageBackupRunner(ParcelFileDescriptor output, PackageInfo target, 851 TransportConnection transportConnection, long quota, int currentOpToken, 852 int transportFlags) throws IOException { 853 mOutput = ParcelFileDescriptor.dup(output.getFileDescriptor()); 854 mTarget = target; 855 mCurrentOpToken = currentOpToken; 856 mEphemeralToken = mUserBackupManagerService.generateRandomIntegerToken(); 857 mPreflight = new SinglePackageBackupPreflight( 858 transportConnection, quota, mEphemeralToken, transportFlags); 859 mPreflightLatch = new CountDownLatch(1); 860 mBackupLatch = new CountDownLatch(1); 861 mPreflightResult = BackupTransport.AGENT_ERROR; 862 mBackupResult = BackupTransport.AGENT_ERROR; 863 mQuota = quota; 864 mTransportFlags = transportFlags; 865 registerTask(target.packageName); 866 } 867 registerTask(String packageName)868 void registerTask(String packageName) { 869 Set<String> packages = Sets.newHashSet(packageName); 870 mOperationStorage.registerOperationForPackages(mCurrentOpToken, OpState.PENDING, 871 packages, this, OpType.BACKUP_WAIT); 872 } 873 unregisterTask()874 void unregisterTask() { 875 mOperationStorage.removeOperation(mCurrentOpToken); 876 } 877 878 @Override run()879 public void run() { 880 FileOutputStream out = new FileOutputStream(mOutput.getFileDescriptor()); 881 mEngine = 882 new FullBackupEngine( 883 mUserBackupManagerService, 884 out, 885 mPreflight, 886 mTarget, 887 false, 888 this, 889 mQuota, 890 mCurrentOpToken, 891 mTransportFlags, 892 mBackupEligibilityRules, 893 mBackupManagerMonitorEventSender); 894 try { 895 try { 896 if (!mIsCancelled) { 897 mPreflightResult = mEngine.preflightCheck(); 898 } 899 } finally { 900 mPreflightLatch.countDown(); 901 } 902 // If there is no error on preflight, continue backup. 903 if (mPreflightResult == BackupTransport.TRANSPORT_OK) { 904 if (!mIsCancelled) { 905 mBackupResult = mEngine.backupOnePackage(); 906 } 907 } 908 } catch (Exception e) { 909 Slog.w(TAG, "Exception during full package backup of " + mTarget.packageName, 910 e); 911 } finally { 912 unregisterTask(); 913 mBackupLatch.countDown(); 914 try { 915 mOutput.close(); 916 } catch (IOException e) { 917 Slog.w(TAG, "Error closing transport pipe in runner"); 918 } 919 } 920 } 921 sendQuotaExceeded(final long backupDataBytes, final long quotaBytes)922 public void sendQuotaExceeded(final long backupDataBytes, final long quotaBytes) { 923 mEngine.sendQuotaExceeded(backupDataBytes, quotaBytes); 924 } 925 926 // If preflight succeeded, returns positive number - preflight size, 927 // otherwise return negative error code. getPreflightResultBlocking()928 long getPreflightResultBlocking() { 929 long fullBackupAgentTimeoutMillis = 930 mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis(); 931 try { 932 mPreflightLatch.await(fullBackupAgentTimeoutMillis, TimeUnit.MILLISECONDS); 933 if (mIsCancelled) { 934 return BackupManager.ERROR_BACKUP_CANCELLED; 935 } 936 if (mPreflightResult == BackupTransport.TRANSPORT_OK) { 937 return mPreflight.getExpectedSizeOrErrorCode(); 938 } else { 939 return mPreflightResult; 940 } 941 } catch (InterruptedException e) { 942 return BackupTransport.AGENT_ERROR; 943 } 944 } 945 getBackupResultBlocking()946 int getBackupResultBlocking() { 947 long fullBackupAgentTimeoutMillis = 948 mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis(); 949 try { 950 mBackupLatch.await(fullBackupAgentTimeoutMillis, TimeUnit.MILLISECONDS); 951 if (mIsCancelled) { 952 return BackupManager.ERROR_BACKUP_CANCELLED; 953 } 954 return mBackupResult; 955 } catch (InterruptedException e) { 956 return BackupTransport.AGENT_ERROR; 957 } 958 } 959 960 961 // BackupRestoreTask interface: specifically, timeout detection 962 963 @Override execute()964 public void execute() { /* intentionally empty */ } 965 966 @Override operationComplete(long result)967 public void operationComplete(long result) { /* intentionally empty */ } 968 969 @Override handleCancel(boolean cancelAll)970 public void handleCancel(boolean cancelAll) { 971 if (DEBUG) { 972 Slog.w(TAG, "Full backup cancel of " + mTarget.packageName); 973 } 974 975 mBackupManagerMonitorEventSender.monitorEvent( 976 BackupManagerMonitor.LOG_EVENT_ID_FULL_BACKUP_CANCEL, 977 mCurrentPackage, BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT, null); 978 mIsCancelled = true; 979 // Cancel tasks spun off by this task. 980 mUserBackupManagerService.handleCancel(mEphemeralToken, cancelAll); 981 mUserBackupManagerService.tearDownAgentAndKill(mTarget.applicationInfo); 982 // Free up everyone waiting on this task and its children. 983 mPreflightLatch.countDown(); 984 mBackupLatch.countDown(); 985 // We are done with this operation. 986 mOperationStorage.removeOperation(mCurrentOpToken); 987 } 988 } 989 } 990