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