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.restore; 18 19 import static com.android.server.backup.BackupManagerService.DEBUG; 20 import static com.android.server.backup.BackupManagerService.MORE_DEBUG; 21 import static com.android.server.backup.BackupManagerService.TAG; 22 import static com.android.server.backup.UserBackupManagerService.BACKUP_MANIFEST_FILENAME; 23 import static com.android.server.backup.UserBackupManagerService.BACKUP_METADATA_FILENAME; 24 import static com.android.server.backup.UserBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE; 25 import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_OPERATION_TIMEOUT; 26 27 import android.annotation.NonNull; 28 import android.app.ApplicationThreadConstants; 29 import android.app.IBackupAgent; 30 import android.app.backup.BackupAgent; 31 import android.app.backup.BackupAnnotations; 32 import android.app.backup.BackupManager; 33 import android.app.backup.FullBackup; 34 import android.app.backup.IBackupManagerMonitor; 35 import android.app.backup.IFullBackupRestoreObserver; 36 import android.content.pm.ApplicationInfo; 37 import android.content.pm.PackageInfo; 38 import android.content.pm.PackageManager.NameNotFoundException; 39 import android.content.pm.PackageManagerInternal; 40 import android.content.pm.Signature; 41 import android.os.ParcelFileDescriptor; 42 import android.os.RemoteException; 43 import android.provider.Settings; 44 import android.system.OsConstants; 45 import android.text.TextUtils; 46 import android.util.Slog; 47 48 import com.android.internal.annotations.GuardedBy; 49 import com.android.internal.annotations.VisibleForTesting; 50 import com.android.server.LocalServices; 51 import com.android.server.backup.BackupAgentTimeoutParameters; 52 import com.android.server.backup.BackupRestoreTask; 53 import com.android.server.backup.FileMetadata; 54 import com.android.server.backup.KeyValueAdbRestoreEngine; 55 import com.android.server.backup.OperationStorage; 56 import com.android.server.backup.OperationStorage.OpType; 57 import com.android.server.backup.UserBackupManagerService; 58 import com.android.server.backup.fullbackup.FullBackupObbConnection; 59 import com.android.server.backup.utils.BackupEligibilityRules; 60 import com.android.server.backup.utils.BytesReadListener; 61 import com.android.server.backup.utils.FullBackupRestoreObserverUtils; 62 import com.android.server.backup.utils.RestoreUtils; 63 import com.android.server.backup.utils.TarBackupReader; 64 65 import java.io.File; 66 import java.io.FileOutputStream; 67 import java.io.IOException; 68 import java.io.InputStream; 69 import java.util.Arrays; 70 import java.util.HashMap; 71 import java.util.HashSet; 72 import java.util.List; 73 import java.util.Objects; 74 75 /** 76 * Full restore engine, used by both adb restore and transport-based full restore. 77 */ 78 public class FullRestoreEngine extends RestoreEngine { 79 80 private final UserBackupManagerService mBackupManagerService; 81 private final OperationStorage mOperationStorage; 82 private final int mUserId; 83 84 // Task in charge of monitoring timeouts 85 private final BackupRestoreTask mMonitorTask; 86 87 private final RestoreDeleteObserver mDeleteObserver = new RestoreDeleteObserver(); 88 89 // Dedicated observer, if any 90 private IFullBackupRestoreObserver mObserver; 91 92 final IBackupManagerMonitor mMonitor; 93 94 // Where we're delivering the file data as we go 95 private IBackupAgent mAgent; 96 97 // Are we permitted to only deliver a specific package's metadata? 98 final PackageInfo mOnlyPackage; 99 100 final boolean mAllowApks; 101 102 // Which package are we currently handling data for? 103 private String mAgentPackage; 104 105 // Info for working with the target app process 106 private ApplicationInfo mTargetApp; 107 108 // Machinery for restoring OBBs 109 private FullBackupObbConnection mObbConnection = null; 110 111 // possible handling states for a given package in the restore dataset 112 private final HashMap<String, RestorePolicy> mPackagePolicies 113 = new HashMap<>(); 114 115 // installer package names for each encountered app, derived from the manifests 116 private final HashMap<String, String> mPackageInstallers = new HashMap<>(); 117 118 // Signatures for a given package found in its manifest file 119 private final HashMap<String, Signature[]> mManifestSignatures 120 = new HashMap<>(); 121 122 // Packages we've already wiped data on when restoring their first file 123 private final HashSet<String> mClearedPackages = new HashSet<>(); 124 125 // Working buffer 126 final byte[] mBuffer; 127 128 // Pipes for moving data 129 private ParcelFileDescriptor[] mPipes = null; 130 private final Object mPipesLock = new Object(); 131 132 // Widget blob to be restored out-of-band 133 private byte[] mWidgetData = null; 134 private long mAppVersion; 135 136 final int mEphemeralOpToken; 137 138 private final BackupAgentTimeoutParameters mAgentTimeoutParameters; 139 private final boolean mIsAdbRestore; 140 @GuardedBy("mPipesLock") 141 private boolean mPipesClosed; 142 private final BackupEligibilityRules mBackupEligibilityRules; 143 144 private FileMetadata mReadOnlyParent = null; 145 FullRestoreEngine( UserBackupManagerService backupManagerService, OperationStorage operationStorage, BackupRestoreTask monitorTask, IFullBackupRestoreObserver observer, IBackupManagerMonitor monitor, PackageInfo onlyPackage, boolean allowApks, int ephemeralOpToken, boolean isAdbRestore, BackupEligibilityRules backupEligibilityRules)146 public FullRestoreEngine( 147 UserBackupManagerService backupManagerService, OperationStorage operationStorage, 148 BackupRestoreTask monitorTask, IFullBackupRestoreObserver observer, 149 IBackupManagerMonitor monitor, PackageInfo onlyPackage, boolean allowApks, 150 int ephemeralOpToken, boolean isAdbRestore, 151 BackupEligibilityRules backupEligibilityRules) { 152 mBackupManagerService = backupManagerService; 153 mOperationStorage = operationStorage; 154 mEphemeralOpToken = ephemeralOpToken; 155 mMonitorTask = monitorTask; 156 mObserver = observer; 157 mMonitor = monitor; 158 mOnlyPackage = onlyPackage; 159 mAllowApks = allowApks; 160 mBuffer = new byte[32 * 1024]; 161 mAgentTimeoutParameters = Objects.requireNonNull( 162 backupManagerService.getAgentTimeoutParameters(), 163 "Timeout parameters cannot be null"); 164 mIsAdbRestore = isAdbRestore; 165 mUserId = backupManagerService.getUserId(); 166 mBackupEligibilityRules = backupEligibilityRules; 167 } 168 169 @VisibleForTesting FullRestoreEngine()170 FullRestoreEngine() { 171 mIsAdbRestore = false; 172 mAllowApks = false; 173 mEphemeralOpToken = 0; 174 mUserId = 0; 175 mBackupEligibilityRules = null; 176 mAgentTimeoutParameters = null; 177 mBuffer = null; 178 mBackupManagerService = null; 179 mOperationStorage = null; 180 mMonitor = null; 181 mMonitorTask = null; 182 mOnlyPackage = null; 183 } 184 getAgent()185 public IBackupAgent getAgent() { 186 return mAgent; 187 } 188 getWidgetData()189 public byte[] getWidgetData() { 190 return mWidgetData; 191 } 192 restoreOneFile(InputStream instream, boolean mustKillAgent, byte[] buffer, PackageInfo onlyPackage, boolean allowApks, int token, IBackupManagerMonitor monitor)193 public boolean restoreOneFile(InputStream instream, boolean mustKillAgent, byte[] buffer, 194 PackageInfo onlyPackage, boolean allowApks, int token, IBackupManagerMonitor monitor) { 195 if (!isRunning()) { 196 Slog.w(TAG, "Restore engine used after halting"); 197 return false; 198 } 199 200 BytesReadListener bytesReadListener = bytesRead -> { }; 201 202 TarBackupReader tarBackupReader = new TarBackupReader(instream, 203 bytesReadListener, monitor); 204 205 FileMetadata info; 206 try { 207 if (MORE_DEBUG) { 208 Slog.v(TAG, "Reading tar header for restoring file"); 209 } 210 info = tarBackupReader.readTarHeaders(); 211 if (info != null) { 212 if (MORE_DEBUG) { 213 info.dump(); 214 } 215 216 final String pkg = info.packageName; 217 if (!pkg.equals(mAgentPackage)) { 218 // In the single-package case, it's a semantic error to expect 219 // one app's data but see a different app's on the wire 220 if (onlyPackage != null) { 221 if (!pkg.equals(onlyPackage.packageName)) { 222 Slog.w(TAG, "Expected data for " + onlyPackage + " but saw " + pkg); 223 setResult(RestoreEngine.TRANSPORT_FAILURE); 224 setRunning(false); 225 return false; 226 } 227 } 228 229 // okay, change in package; set up our various 230 // bookkeeping if we haven't seen it yet 231 if (!mPackagePolicies.containsKey(pkg)) { 232 mPackagePolicies.put(pkg, RestorePolicy.IGNORE); 233 } 234 235 // Clean up the previous agent relationship if necessary, 236 // and let the observer know we're considering a new app. 237 if (mAgent != null) { 238 if (DEBUG) { 239 Slog.d(TAG, "Saw new package; finalizing old one"); 240 } 241 // Now we're really done 242 tearDownPipes(); 243 tearDownAgent(mTargetApp, mIsAdbRestore); 244 mTargetApp = null; 245 mAgentPackage = null; 246 } 247 } 248 249 if (info.path.equals(BACKUP_MANIFEST_FILENAME)) { 250 Signature[] signatures = tarBackupReader.readAppManifestAndReturnSignatures( 251 info); 252 // readAppManifestAndReturnSignatures() will have extracted the version from 253 // the manifest, so we save it to use in adb key-value restore later. 254 mAppVersion = info.version; 255 PackageManagerInternal pmi = LocalServices.getService( 256 PackageManagerInternal.class); 257 RestorePolicy restorePolicy = tarBackupReader.chooseRestorePolicy( 258 mBackupManagerService.getPackageManager(), allowApks, info, signatures, 259 pmi, mUserId, mBackupEligibilityRules); 260 mManifestSignatures.put(info.packageName, signatures); 261 mPackagePolicies.put(pkg, restorePolicy); 262 mPackageInstallers.put(pkg, info.installerPackageName); 263 // We've read only the manifest content itself at this point, 264 // so consume the footer before looping around to the next 265 // input file 266 tarBackupReader.skipTarPadding(info.size); 267 mObserver = FullBackupRestoreObserverUtils.sendOnRestorePackage(mObserver, pkg); 268 } else if (info.path.equals(BACKUP_METADATA_FILENAME)) { 269 // Metadata blobs! 270 tarBackupReader.readMetadata(info); 271 272 // The following only exist because we want to keep refactoring as safe as 273 // possible, without changing too much. 274 // TODO: Refactor, so that there are no funny things like this. 275 // This is read during TarBackupReader.readMetadata(). 276 mWidgetData = tarBackupReader.getWidgetData(); 277 // This can be nulled during TarBackupReader.readMetadata(). 278 monitor = tarBackupReader.getMonitor(); 279 280 tarBackupReader.skipTarPadding(info.size); 281 } else { 282 // Non-manifest, so it's actual file data. Is this a package 283 // we're ignoring? 284 boolean okay = true; 285 RestorePolicy policy = mPackagePolicies.get(pkg); 286 switch (policy) { 287 case IGNORE: 288 okay = false; 289 break; 290 291 case ACCEPT_IF_APK: 292 // If we're in accept-if-apk state, then the first file we 293 // see MUST be the apk. 294 if (info.domain.equals(FullBackup.APK_TREE_TOKEN)) { 295 if (DEBUG) { 296 Slog.d(TAG, "APK file; installing"); 297 } 298 // Try to install the app. 299 String installerPackageName = mPackageInstallers.get(pkg); 300 boolean isSuccessfullyInstalled = RestoreUtils.installApk( 301 instream, mBackupManagerService.getContext(), 302 mDeleteObserver, mManifestSignatures, 303 mPackagePolicies, info, installerPackageName, 304 bytesReadListener, mUserId); 305 // good to go; promote to ACCEPT 306 mPackagePolicies.put(pkg, isSuccessfullyInstalled 307 ? RestorePolicy.ACCEPT 308 : RestorePolicy.IGNORE); 309 // At this point we've consumed this file entry 310 // ourselves, so just strip the tar footer and 311 // go on to the next file in the input stream 312 tarBackupReader.skipTarPadding(info.size); 313 return true; 314 } else { 315 // File data before (or without) the apk. We can't 316 // handle it coherently in this case so ignore it. 317 mPackagePolicies.put(pkg, RestorePolicy.IGNORE); 318 okay = false; 319 } 320 break; 321 322 case ACCEPT: 323 if (info.domain.equals(FullBackup.APK_TREE_TOKEN)) { 324 if (DEBUG) { 325 Slog.d(TAG, "apk present but ACCEPT"); 326 } 327 // we can take the data without the apk, so we 328 // *want* to do so. skip the apk by declaring this 329 // one file not-okay without changing the restore 330 // policy for the package. 331 okay = false; 332 } 333 break; 334 335 default: 336 // Something has gone dreadfully wrong when determining 337 // the restore policy from the manifest. Ignore the 338 // rest of this package's data. 339 Slog.e(TAG, "Invalid policy from manifest"); 340 okay = false; 341 mPackagePolicies.put(pkg, RestorePolicy.IGNORE); 342 break; 343 } 344 345 // Is it a *file* we need to drop or is it not a canonical path? 346 if (!isRestorableFile(info) || !isCanonicalFilePath(info.path)) { 347 okay = false; 348 } 349 350 // If the policy is satisfied, go ahead and set up to pipe the 351 // data to the agent. 352 if (MORE_DEBUG && okay && mAgent != null) { 353 Slog.i(TAG, "Reusing existing agent instance"); 354 } 355 if (okay && mAgent == null) { 356 if (MORE_DEBUG) { 357 Slog.d(TAG, "Need to launch agent for " + pkg); 358 } 359 360 try { 361 mTargetApp = 362 mBackupManagerService.getPackageManager() 363 .getApplicationInfoAsUser(pkg, 0, mUserId); 364 365 // If we haven't sent any data to this app yet, we probably 366 // need to clear it first. Check that. 367 if (!mClearedPackages.contains(pkg)) { 368 // Apps with their own backup agents are responsible for coherently 369 // managing a full restore. 370 // In some rare cases they can't, especially in case of deferred 371 // restore. In this case check whether this app should be forced to 372 // clear up. 373 // TODO: Fix this properly with manifest parameter. 374 boolean forceClear = shouldForceClearAppDataOnFullRestore( 375 mTargetApp.packageName); 376 if (mTargetApp.backupAgentName == null || forceClear) { 377 if (DEBUG) { 378 Slog.d(TAG, 379 "Clearing app data preparatory to full restore"); 380 } 381 mBackupManagerService.clearApplicationDataBeforeRestore(pkg); 382 } else { 383 if (MORE_DEBUG) { 384 Slog.d(TAG, "backup agent (" 385 + mTargetApp.backupAgentName + ") => no clear"); 386 } 387 } 388 mClearedPackages.add(pkg); 389 } else { 390 if (MORE_DEBUG) { 391 Slog.d(TAG, "We've initialized this app already; no clear " 392 + "required"); 393 } 394 } 395 396 // All set; now set up the IPC and launch the agent 397 setUpPipes(); 398 mAgent = mBackupManagerService.bindToAgentSynchronous(mTargetApp, 399 FullBackup.KEY_VALUE_DATA_TOKEN.equals(info.domain) 400 ? ApplicationThreadConstants.BACKUP_MODE_RESTORE 401 : ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL, 402 mBackupEligibilityRules.getBackupDestination()); 403 mAgentPackage = pkg; 404 } catch (IOException | NameNotFoundException e) { 405 // fall through to error handling 406 } 407 408 if (mAgent == null) { 409 Slog.e(TAG, "Unable to create agent for " + pkg); 410 okay = false; 411 tearDownPipes(); 412 mPackagePolicies.put(pkg, RestorePolicy.IGNORE); 413 } 414 } 415 416 // Make sure we never give data to the wrong app. This 417 // should never happen but a little paranoia here won't go amiss. 418 if (okay && !pkg.equals(mAgentPackage)) { 419 Slog.e(TAG, "Restoring data for " + pkg 420 + " but agent is for " + mAgentPackage); 421 okay = false; 422 } 423 424 if (shouldSkipReadOnlyDir(info)) { 425 // b/194894879: We don't support restore of read-only dirs. 426 okay = false; 427 } 428 429 // At this point we have an agent ready to handle the full 430 // restore data as well as a pipe for sending data to 431 // that agent. Tell the agent to start reading from the 432 // pipe. 433 if (okay) { 434 boolean agentSuccess = true; 435 long toCopy = info.size; 436 final boolean isSharedStorage = pkg.equals(SHARED_BACKUP_AGENT_PACKAGE); 437 final long timeout = isSharedStorage ? 438 mAgentTimeoutParameters.getSharedBackupAgentTimeoutMillis() : 439 mAgentTimeoutParameters.getRestoreAgentTimeoutMillis( 440 mTargetApp.uid); 441 try { 442 mBackupManagerService.prepareOperationTimeout(token, 443 timeout, 444 mMonitorTask, 445 OpType.RESTORE_WAIT); 446 447 if (FullBackup.OBB_TREE_TOKEN.equals(info.domain)) { 448 if (DEBUG) { 449 Slog.d(TAG, "Restoring OBB file for " + pkg 450 + " : " + info.path); 451 } 452 mObbConnection.restoreObbFile(pkg, mPipes[0], 453 info.size, info.type, info.path, info.mode, 454 info.mtime, token, 455 mBackupManagerService.getBackupManagerBinder()); 456 } else if (FullBackup.KEY_VALUE_DATA_TOKEN.equals(info.domain)) { 457 // This is only possible during adb restore. 458 // TODO: Refactor to clearly separate the flows. 459 if (DEBUG) { 460 Slog.d(TAG, "Restoring key-value file for " + pkg 461 + " : " + info.path); 462 } 463 // Set the version saved from manifest entry. 464 info.version = mAppVersion; 465 KeyValueAdbRestoreEngine restoreEngine = 466 new KeyValueAdbRestoreEngine( 467 mBackupManagerService, 468 mBackupManagerService.getDataDir(), info, mPipes[0], 469 mAgent, token); 470 new Thread(restoreEngine, "restore-key-value-runner").start(); 471 } else { 472 if (MORE_DEBUG) { 473 Slog.d(TAG, "Invoking agent to restore file " + info.path); 474 } 475 // fire up the app's agent listening on the socket. If 476 // the agent is running in the system process we can't 477 // just invoke it asynchronously, so we provide a thread 478 // for it here. 479 if (mTargetApp.processName.equals("system")) { 480 Slog.d(TAG, "system process agent - spinning a thread"); 481 RestoreFileRunnable runner = new RestoreFileRunnable( 482 mBackupManagerService, mAgent, info, mPipes[0], token); 483 new Thread(runner, "restore-sys-runner").start(); 484 } else { 485 mAgent.doRestoreFile(mPipes[0], info.size, info.type, 486 info.domain, info.path, info.mode, info.mtime, 487 token, mBackupManagerService.getBackupManagerBinder()); 488 } 489 } 490 } catch (IOException e) { 491 // couldn't dup the socket for a process-local restore 492 Slog.d(TAG, "Couldn't establish restore"); 493 agentSuccess = false; 494 okay = false; 495 } catch (RemoteException e) { 496 // whoops, remote entity went away. We'll eat the content 497 // ourselves, then, and not copy it over. 498 Slog.e(TAG, "Agent crashed during full restore"); 499 agentSuccess = false; 500 okay = false; 501 } 502 503 // Copy over the data if the agent is still good 504 if (okay) { 505 if (MORE_DEBUG) { 506 Slog.v(TAG, " copying to restore agent: " + toCopy + " bytes"); 507 } 508 boolean pipeOkay = true; 509 FileOutputStream pipe = new FileOutputStream( 510 mPipes[1].getFileDescriptor()); 511 while (toCopy > 0) { 512 int toRead = (toCopy > buffer.length) 513 ? buffer.length : (int) toCopy; 514 int nRead = instream.read(buffer, 0, toRead); 515 if (nRead <= 0) { 516 break; 517 } 518 toCopy -= nRead; 519 520 // send it to the output pipe as long as things 521 // are still good 522 if (pipeOkay) { 523 try { 524 pipe.write(buffer, 0, nRead); 525 } catch (IOException e) { 526 Slog.e(TAG, "Failed to write to restore pipe: " 527 + e.getMessage()); 528 pipeOkay = false; 529 } 530 } 531 } 532 533 // done sending that file! Now we just need to consume 534 // the delta from info.size to the end of block. 535 tarBackupReader.skipTarPadding(info.size); 536 537 // and now that we've sent it all, wait for the remote 538 // side to acknowledge receipt 539 agentSuccess = mBackupManagerService.waitUntilOperationComplete(token); 540 } 541 542 // okay, if the remote end failed at any point, deal with 543 // it by ignoring the rest of the restore on it 544 if (!agentSuccess) { 545 Slog.w(TAG, "Agent failure restoring " + pkg + "; ending restore"); 546 mBackupManagerService.getBackupHandler().removeMessages( 547 MSG_RESTORE_OPERATION_TIMEOUT); 548 tearDownPipes(); 549 tearDownAgent(mTargetApp, false); 550 mAgent = null; 551 mPackagePolicies.put(pkg, RestorePolicy.IGNORE); 552 553 // If this was a single-package restore, we halt immediately 554 // with an agent error under these circumstances 555 if (onlyPackage != null) { 556 setResult(RestoreEngine.TARGET_FAILURE); 557 setRunning(false); 558 return false; 559 } 560 } 561 } 562 563 // Problems setting up the agent communication, an explicitly 564 // dropped file, or an already-ignored package: skip to the 565 // next stream entry by reading and discarding this file. 566 if (!okay) { 567 if (MORE_DEBUG) { 568 Slog.d(TAG, "[discarding file content]"); 569 } 570 long bytesToConsume = (info.size + 511) & ~511; 571 while (bytesToConsume > 0) { 572 int toRead = (bytesToConsume > buffer.length) 573 ? buffer.length : (int) bytesToConsume; 574 long nRead = instream.read(buffer, 0, toRead); 575 if (nRead <= 0) { 576 break; 577 } 578 bytesToConsume -= nRead; 579 } 580 } 581 } 582 } 583 } catch (IOException e) { 584 if (DEBUG) { 585 Slog.w(TAG, "io exception on restore socket read: " + e.getMessage()); 586 } 587 setResult(RestoreEngine.TRANSPORT_FAILURE); 588 info = null; 589 } 590 591 // If we got here we're either running smoothly or we've finished 592 if (info == null) { 593 if (MORE_DEBUG) { 594 Slog.i(TAG, "No [more] data for this package; tearing down"); 595 } 596 tearDownPipes(); 597 setRunning(false); 598 if (mustKillAgent) { 599 tearDownAgent(mTargetApp, mIsAdbRestore); 600 } 601 } 602 return (info != null); 603 } 604 shouldSkipReadOnlyDir(FileMetadata info)605 boolean shouldSkipReadOnlyDir(FileMetadata info) { 606 if (isValidParent(mReadOnlyParent, info)) { 607 // This file has a read-only parent directory, we shouldn't 608 // restore it. 609 return true; 610 } else { 611 // We're now in a different branch of the file tree, update the parent 612 // value. 613 if (isReadOnlyDir(info)) { 614 // Current directory is read-only. Remember it so that we can skip all 615 // of its contents. 616 mReadOnlyParent = info; 617 Slog.w(TAG, "Skipping restore of " + info.path + " and its contents as " 618 + "read-only dirs are currently not supported."); 619 return true; 620 } else { 621 mReadOnlyParent = null; 622 } 623 } 624 625 return false; 626 } 627 isValidParent(FileMetadata parentDir, @NonNull FileMetadata childDir)628 private static boolean isValidParent(FileMetadata parentDir, @NonNull FileMetadata childDir) { 629 return parentDir != null 630 && childDir.packageName.equals(parentDir.packageName) 631 && childDir.domain.equals(parentDir.domain) 632 && childDir.path.startsWith(getPathWithTrailingSeparator(parentDir.path)); 633 } 634 getPathWithTrailingSeparator(String path)635 private static String getPathWithTrailingSeparator(String path) { 636 return path.endsWith(File.separator) ? path : path + File.separator; 637 } 638 isReadOnlyDir(FileMetadata file)639 private static boolean isReadOnlyDir(FileMetadata file) { 640 // Check if owner has 'write' bit in the file's mode value (see 'man -7 inode' for details). 641 return file.type == BackupAgent.TYPE_DIRECTORY && (file.mode & OsConstants.S_IWUSR) == 0; 642 } 643 setUpPipes()644 private void setUpPipes() throws IOException { 645 synchronized (mPipesLock) { 646 mPipes = ParcelFileDescriptor.createPipe(); 647 mPipesClosed = false; 648 } 649 } 650 tearDownPipes()651 private void tearDownPipes() { 652 // Teardown might arise from the inline restore processing or from the asynchronous 653 // timeout mechanism, and these might race. Make sure we don't try to close and 654 // null out the pipes twice. 655 synchronized (mPipesLock) { 656 if (!mPipesClosed && mPipes != null) { 657 try { 658 mPipes[0].close(); 659 mPipes[1].close(); 660 661 mPipesClosed = true; 662 } catch (IOException e) { 663 Slog.w(TAG, "Couldn't close agent pipes", e); 664 } 665 } 666 } 667 } 668 tearDownAgent(ApplicationInfo app, boolean doRestoreFinished)669 private void tearDownAgent(ApplicationInfo app, boolean doRestoreFinished) { 670 if (mAgent != null) { 671 try { 672 // In the adb restore case, we do restore-finished here 673 if (doRestoreFinished) { 674 final int token = mBackupManagerService.generateRandomIntegerToken(); 675 long fullBackupAgentTimeoutMillis = 676 mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis(); 677 final AdbRestoreFinishedLatch latch = new AdbRestoreFinishedLatch( 678 mBackupManagerService, mOperationStorage, token); 679 mBackupManagerService.prepareOperationTimeout( 680 token, fullBackupAgentTimeoutMillis, latch, OpType.RESTORE_WAIT); 681 if (mTargetApp.processName.equals("system")) { 682 if (MORE_DEBUG) { 683 Slog.d(TAG, "system agent - restoreFinished on thread"); 684 } 685 Runnable runner = new AdbRestoreFinishedRunnable(mAgent, token, 686 mBackupManagerService); 687 new Thread(runner, "restore-sys-finished-runner").start(); 688 } else { 689 mAgent.doRestoreFinished(token, 690 mBackupManagerService.getBackupManagerBinder()); 691 } 692 693 latch.await(); 694 } 695 696 mBackupManagerService.tearDownAgentAndKill(app); 697 } catch (RemoteException e) { 698 Slog.d(TAG, "Lost app trying to shut down"); 699 } 700 mAgent = null; 701 } 702 } 703 handleTimeout()704 void handleTimeout() { 705 tearDownPipes(); 706 setResult(RestoreEngine.TARGET_FAILURE); 707 setRunning(false); 708 } 709 isRestorableFile(FileMetadata info)710 private boolean isRestorableFile(FileMetadata info) { 711 if (mBackupEligibilityRules.getBackupDestination() 712 == BackupAnnotations.BackupDestination.DEVICE_TRANSFER) { 713 // Everything is eligible for device-to-device migration. 714 return true; 715 } 716 if (FullBackup.CACHE_TREE_TOKEN.equals(info.domain)) { 717 if (MORE_DEBUG) { 718 Slog.i(TAG, "Dropping cache file path " + info.path); 719 } 720 return false; 721 } 722 723 if (FullBackup.ROOT_TREE_TOKEN.equals(info.domain)) { 724 // It's possible this is "no-backup" dir contents in an archive stream 725 // produced on a device running a version of the OS that predates that 726 // API. Respect the no-backup intention and don't let the data get to 727 // the app. 728 if (info.path.startsWith("no_backup/")) { 729 if (MORE_DEBUG) { 730 Slog.i(TAG, "Dropping no_backup file path " + info.path); 731 } 732 return false; 733 } 734 } 735 736 // Otherwise we think this file is good to go 737 return true; 738 } 739 isCanonicalFilePath(String path)740 private static boolean isCanonicalFilePath(String path) { 741 if (path.contains("..") || path.contains("//")) { 742 if (MORE_DEBUG) { 743 Slog.w(TAG, "Dropping invalid path " + path); 744 } 745 return false; 746 } 747 748 return true; 749 } 750 751 /** 752 * Returns whether the package is in the list of the packages for which clear app data should 753 * be called despite the fact that they have backup agent. 754 * 755 * <p>The list is read from {@link Settings.Secure#PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE}. 756 */ shouldForceClearAppDataOnFullRestore(String packageName)757 private boolean shouldForceClearAppDataOnFullRestore(String packageName) { 758 String packageListString = Settings.Secure.getStringForUser( 759 mBackupManagerService.getContext().getContentResolver(), 760 Settings.Secure.PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE, 761 mUserId); 762 if (TextUtils.isEmpty(packageListString)) { 763 return false; 764 } 765 766 List<String> packages = Arrays.asList(packageListString.split(";")); 767 return packages.contains(packageName); 768 } 769 sendOnRestorePackage(String name)770 void sendOnRestorePackage(String name) { 771 if (mObserver != null) { 772 try { 773 // TODO: use a more user-friendly name string 774 mObserver.onRestorePackage(name); 775 } catch (RemoteException e) { 776 Slog.w(TAG, "full restore observer went away: restorePackage"); 777 mObserver = null; 778 } 779 } 780 } 781 } 782