BackupManagerService.java revision deb244d3e552fb388dad07d624ae3f38a61d3c23
1/* 2 * Copyright (C) 2009 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 17package com.android.server.backup; 18 19import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_NAME; 20import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_VERSION; 21import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_OLD_VERSION; 22import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_POLICY_ALLOW_APKS; 23import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_MANIFEST_PACKAGE_NAME; 24import static android.app.backup.BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT; 25import static android.app.backup.BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY; 26import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER; 27import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_FULL_RESTORE_SIGNATURE_MISMATCH; 28import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_SYSTEM_APP_NO_AGENT; 29import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_FULL_RESTORE_ALLOW_BACKUP_FALSE; 30import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_APK_NOT_INSTALLED; 31import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_CANNOT_RESTORE_WITHOUT_APK; 32import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_MISSING_SIGNATURE; 33import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_EXPECTED_DIFFERENT_PACKAGE; 34import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_RESTORE_ANY_VERSION; 35import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_VERSIONS_MATCH; 36import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND; 37 38import android.app.ActivityManager; 39import android.app.AlarmManager; 40import android.app.AppGlobals; 41import android.app.ApplicationThreadConstants; 42import android.app.IActivityManager; 43import android.app.IBackupAgent; 44import android.app.PackageInstallObserver; 45import android.app.PendingIntent; 46import android.app.backup.BackupAgent; 47import android.app.backup.BackupDataInput; 48import android.app.backup.BackupDataOutput; 49import android.app.backup.BackupManager; 50import android.app.backup.BackupManagerMonitor; 51import android.app.backup.BackupProgress; 52import android.app.backup.BackupTransport; 53import android.app.backup.FullBackup; 54import android.app.backup.FullBackupDataOutput; 55import android.app.backup.IBackupManager; 56import android.app.backup.IBackupManagerMonitor; 57import android.app.backup.IBackupObserver; 58import android.app.backup.IFullBackupRestoreObserver; 59import android.app.backup.IRestoreObserver; 60import android.app.backup.IRestoreSession; 61import android.app.backup.ISelectBackupTransportCallback; 62import android.app.backup.RestoreDescription; 63import android.app.backup.RestoreSet; 64import android.app.backup.SelectBackupTransportCallback; 65import android.content.ActivityNotFoundException; 66import android.content.BroadcastReceiver; 67import android.content.ComponentName; 68import android.content.ContentResolver; 69import android.content.Context; 70import android.content.Intent; 71import android.content.IntentFilter; 72import android.content.ServiceConnection; 73import android.content.pm.ApplicationInfo; 74import android.content.pm.IPackageDataObserver; 75import android.content.pm.IPackageDeleteObserver; 76import android.content.pm.IPackageManager; 77import android.content.pm.PackageInfo; 78import android.content.pm.PackageManager; 79import android.content.pm.PackageManager.NameNotFoundException; 80import android.content.pm.Signature; 81import android.database.ContentObserver; 82import android.net.Uri; 83import android.os.Binder; 84import android.os.Build; 85import android.os.Bundle; 86import android.os.Environment; 87import android.os.Environment.UserEnvironment; 88import android.os.Handler; 89import android.os.HandlerThread; 90import android.os.IBinder; 91import android.os.Looper; 92import android.os.Message; 93import android.os.ParcelFileDescriptor; 94import android.os.PowerManager; 95import android.os.Process; 96import android.os.RemoteException; 97import android.os.SELinux; 98import android.os.ServiceManager; 99import android.os.SystemClock; 100import android.os.UserHandle; 101import android.os.WorkSource; 102import android.os.storage.IStorageManager; 103import android.os.storage.StorageManager; 104import android.provider.Settings; 105import android.system.ErrnoException; 106import android.system.Os; 107import android.text.TextUtils; 108import android.util.AtomicFile; 109import android.util.EventLog; 110import android.util.Log; 111import android.util.Pair; 112import android.util.Slog; 113import android.util.SparseArray; 114import android.util.StringBuilderPrinter; 115 116import com.android.internal.annotations.GuardedBy; 117import com.android.internal.backup.IBackupTransport; 118import com.android.internal.backup.IObbBackupService; 119import com.android.server.AppWidgetBackupBridge; 120import com.android.server.EventLogTags; 121import com.android.server.SystemConfig; 122import com.android.server.SystemService; 123import com.android.server.backup.PackageManagerBackupAgent.Metadata; 124 125import libcore.io.IoUtils; 126 127import java.io.BufferedInputStream; 128import java.io.BufferedOutputStream; 129import java.io.ByteArrayInputStream; 130import java.io.ByteArrayOutputStream; 131import java.io.DataInputStream; 132import java.io.DataOutputStream; 133import java.io.EOFException; 134import java.io.File; 135import java.io.FileDescriptor; 136import java.io.FileInputStream; 137import java.io.FileNotFoundException; 138import java.io.FileOutputStream; 139import java.io.IOException; 140import java.io.InputStream; 141import java.io.OutputStream; 142import java.io.PrintWriter; 143import java.io.RandomAccessFile; 144import java.security.InvalidAlgorithmParameterException; 145import java.security.InvalidKeyException; 146import java.security.Key; 147import java.security.MessageDigest; 148import java.security.NoSuchAlgorithmException; 149import java.security.SecureRandom; 150import java.security.spec.InvalidKeySpecException; 151import java.security.spec.KeySpec; 152import java.text.SimpleDateFormat; 153import java.util.ArrayDeque; 154import java.util.ArrayList; 155import java.util.Arrays; 156import java.util.Collections; 157import java.util.Date; 158import java.util.HashMap; 159import java.util.HashSet; 160import java.util.Iterator; 161import java.util.List; 162import java.util.Map.Entry; 163import java.util.Objects; 164import java.util.Queue; 165import java.util.Random; 166import java.util.Set; 167import java.util.TreeMap; 168import java.util.concurrent.CountDownLatch; 169import java.util.concurrent.TimeUnit; 170import java.util.concurrent.atomic.AtomicBoolean; 171import java.util.concurrent.atomic.AtomicInteger; 172import java.util.concurrent.atomic.AtomicLong; 173import java.util.zip.Deflater; 174import java.util.zip.DeflaterOutputStream; 175import java.util.zip.InflaterInputStream; 176 177import javax.crypto.BadPaddingException; 178import javax.crypto.Cipher; 179import javax.crypto.CipherInputStream; 180import javax.crypto.CipherOutputStream; 181import javax.crypto.IllegalBlockSizeException; 182import javax.crypto.NoSuchPaddingException; 183import javax.crypto.SecretKey; 184import javax.crypto.SecretKeyFactory; 185import javax.crypto.spec.IvParameterSpec; 186import javax.crypto.spec.PBEKeySpec; 187import javax.crypto.spec.SecretKeySpec; 188 189public class BackupManagerService { 190 191 private static final String TAG = "BackupManagerService"; 192 static final boolean DEBUG = true; 193 static final boolean MORE_DEBUG = false; 194 static final boolean DEBUG_SCHEDULING = MORE_DEBUG || true; 195 196 // File containing backup-enabled state. Contains a single byte; 197 // nonzero == enabled. File missing or contains a zero byte == disabled. 198 static final String BACKUP_ENABLE_FILE = "backup_enabled"; 199 200 // System-private key used for backing up an app's widget state. Must 201 // begin with U+FFxx by convention (we reserve all keys starting 202 // with U+FF00 or higher for system use). 203 static final String KEY_WIDGET_STATE = "\uffed\uffedwidget"; 204 205 // Historical and current algorithm names 206 static final String PBKDF_CURRENT = "PBKDF2WithHmacSHA1"; 207 static final String PBKDF_FALLBACK = "PBKDF2WithHmacSHA1And8bit"; 208 209 // Name and current contents version of the full-backup manifest file 210 // 211 // Manifest version history: 212 // 213 // 1 : initial release 214 static final String BACKUP_MANIFEST_FILENAME = "_manifest"; 215 static final int BACKUP_MANIFEST_VERSION = 1; 216 217 // External archive format version history: 218 // 219 // 1 : initial release 220 // 2 : no format change per se; version bump to facilitate PBKDF2 version skew detection 221 // 3 : introduced "_meta" metadata file; no other format change per se 222 // 4 : added support for new device-encrypted storage locations 223 static final int BACKUP_FILE_VERSION = 4; 224 static final String BACKUP_FILE_HEADER_MAGIC = "ANDROID BACKUP\n"; 225 static final int BACKUP_PW_FILE_VERSION = 2; 226 static final String BACKUP_METADATA_FILENAME = "_meta"; 227 static final int BACKUP_METADATA_VERSION = 1; 228 static final int BACKUP_WIDGET_METADATA_TOKEN = 0x01FFED01; 229 static final boolean COMPRESS_FULL_BACKUPS = true; // should be true in production 230 231 static final String SETTINGS_PACKAGE = "com.android.providers.settings"; 232 static final String SHARED_BACKUP_AGENT_PACKAGE = "com.android.sharedstoragebackup"; 233 static final String SERVICE_ACTION_TRANSPORT_HOST = "android.backup.TRANSPORT_HOST"; 234 235 // Retry interval for clear/init when the transport is unavailable 236 private static final long TRANSPORT_RETRY_INTERVAL = 1 * AlarmManager.INTERVAL_HOUR; 237 238 private static final String RUN_BACKUP_ACTION = "android.app.backup.intent.RUN"; 239 private static final String RUN_INITIALIZE_ACTION = "android.app.backup.intent.INIT"; 240 private static final int MSG_RUN_BACKUP = 1; 241 private static final int MSG_RUN_ADB_BACKUP = 2; 242 private static final int MSG_RUN_RESTORE = 3; 243 private static final int MSG_RUN_CLEAR = 4; 244 private static final int MSG_RUN_INITIALIZE = 5; 245 private static final int MSG_RUN_GET_RESTORE_SETS = 6; 246 private static final int MSG_RESTORE_SESSION_TIMEOUT = 8; 247 private static final int MSG_FULL_CONFIRMATION_TIMEOUT = 9; 248 private static final int MSG_RUN_ADB_RESTORE = 10; 249 private static final int MSG_RETRY_INIT = 11; 250 private static final int MSG_RETRY_CLEAR = 12; 251 private static final int MSG_WIDGET_BROADCAST = 13; 252 private static final int MSG_RUN_FULL_TRANSPORT_BACKUP = 14; 253 private static final int MSG_REQUEST_BACKUP = 15; 254 private static final int MSG_SCHEDULE_BACKUP_PACKAGE = 16; 255 private static final int MSG_BACKUP_OPERATION_TIMEOUT = 17; 256 private static final int MSG_RESTORE_OPERATION_TIMEOUT = 18; 257 258 // backup task state machine tick 259 static final int MSG_BACKUP_RESTORE_STEP = 20; 260 static final int MSG_OP_COMPLETE = 21; 261 262 // Timeout interval for deciding that a bind or clear-data has taken too long 263 static final long TIMEOUT_INTERVAL = 10 * 1000; 264 265 // Timeout intervals for agent backup & restore operations 266 static final long TIMEOUT_BACKUP_INTERVAL = 30 * 1000; 267 static final long TIMEOUT_FULL_BACKUP_INTERVAL = 5 * 60 * 1000; 268 static final long TIMEOUT_SHARED_BACKUP_INTERVAL = 30 * 60 * 1000; 269 static final long TIMEOUT_RESTORE_INTERVAL = 60 * 1000; 270 static final long TIMEOUT_RESTORE_FINISHED_INTERVAL = 30 * 1000; 271 272 // User confirmation timeout for a full backup/restore operation. It's this long in 273 // order to give them time to enter the backup password. 274 static final long TIMEOUT_FULL_CONFIRMATION = 60 * 1000; 275 276 // How long between attempts to perform a full-data backup of any given app 277 static final long MIN_FULL_BACKUP_INTERVAL = 1000 * 60 * 60 * 24; // one day 278 279 // If an app is busy when we want to do a full-data backup, how long to defer the retry. 280 // This is fuzzed, so there are two parameters; backoff_min + Rand[0, backoff_fuzz) 281 static final long BUSY_BACKOFF_MIN_MILLIS = 1000 * 60 * 60; // one hour 282 static final int BUSY_BACKOFF_FUZZ = 1000 * 60 * 60 * 2; // two hours 283 284 Context mContext; 285 private PackageManager mPackageManager; 286 IPackageManager mPackageManagerBinder; 287 private IActivityManager mActivityManager; 288 private PowerManager mPowerManager; 289 private AlarmManager mAlarmManager; 290 private IStorageManager mStorageManager; 291 IBackupManager mBackupManagerBinder; 292 293 private final TransportManager mTransportManager; 294 295 boolean mEnabled; // access to this is synchronized on 'this' 296 boolean mProvisioned; 297 boolean mAutoRestore; 298 PowerManager.WakeLock mWakelock; 299 HandlerThread mHandlerThread; 300 BackupHandler mBackupHandler; 301 PendingIntent mRunBackupIntent, mRunInitIntent; 302 BroadcastReceiver mRunBackupReceiver, mRunInitReceiver; 303 // map UIDs to the set of participating packages under that UID 304 final SparseArray<HashSet<String>> mBackupParticipants 305 = new SparseArray<HashSet<String>>(); 306 // set of backup services that have pending changes 307 class BackupRequest { 308 public String packageName; 309 310 BackupRequest(String pkgName) { 311 packageName = pkgName; 312 } 313 314 public String toString() { 315 return "BackupRequest{pkg=" + packageName + "}"; 316 } 317 } 318 // Backups that we haven't started yet. Keys are package names. 319 HashMap<String,BackupRequest> mPendingBackups 320 = new HashMap<String,BackupRequest>(); 321 322 // Pseudoname that we use for the Package Manager metadata "package" 323 static final String PACKAGE_MANAGER_SENTINEL = "@pm@"; 324 325 // locking around the pending-backup management 326 final Object mQueueLock = new Object(); 327 328 // The thread performing the sequence of queued backups binds to each app's agent 329 // in succession. Bind notifications are asynchronously delivered through the 330 // Activity Manager; use this lock object to signal when a requested binding has 331 // completed. 332 final Object mAgentConnectLock = new Object(); 333 IBackupAgent mConnectedAgent; 334 volatile boolean mBackupRunning; 335 volatile boolean mConnecting; 336 volatile long mLastBackupPass; 337 338 // For debugging, we maintain a progress trace of operations during backup 339 static final boolean DEBUG_BACKUP_TRACE = true; 340 final List<String> mBackupTrace = new ArrayList<String>(); 341 342 // A similar synchronization mechanism around clearing apps' data for restore 343 final Object mClearDataLock = new Object(); 344 volatile boolean mClearingData; 345 346 @GuardedBy("mPendingRestores") 347 private boolean mIsRestoreInProgress; 348 @GuardedBy("mPendingRestores") 349 private final Queue<PerformUnifiedRestoreTask> mPendingRestores = new ArrayDeque<>(); 350 351 ActiveRestoreSession mActiveRestoreSession; 352 353 // Watch the device provisioning operation during setup 354 ContentObserver mProvisionedObserver; 355 356 // The published binder is actually to a singleton trampoline object that calls 357 // through to the proper code. This indirection lets us turn down the heavy 358 // implementation object on the fly without disturbing binders that have been 359 // cached elsewhere in the system. 360 static Trampoline sInstance; 361 static Trampoline getInstance() { 362 // Always constructed during system bringup, so no need to lazy-init 363 return sInstance; 364 } 365 366 public static final class Lifecycle extends SystemService { 367 368 public Lifecycle(Context context) { 369 super(context); 370 sInstance = new Trampoline(context); 371 } 372 373 @Override 374 public void onStart() { 375 publishBinderService(Context.BACKUP_SERVICE, sInstance); 376 } 377 378 @Override 379 public void onUnlockUser(int userId) { 380 if (userId == UserHandle.USER_SYSTEM) { 381 sInstance.initialize(userId); 382 383 // Migrate legacy setting 384 if (!backupSettingMigrated(userId)) { 385 if (DEBUG) { 386 Slog.i(TAG, "Backup enable apparently not migrated"); 387 } 388 final ContentResolver r = sInstance.mContext.getContentResolver(); 389 final int enableState = Settings.Secure.getIntForUser(r, 390 Settings.Secure.BACKUP_ENABLED, -1, userId); 391 if (enableState >= 0) { 392 if (DEBUG) { 393 Slog.i(TAG, "Migrating enable state " + (enableState != 0)); 394 } 395 writeBackupEnableState(enableState != 0, userId); 396 Settings.Secure.putStringForUser(r, 397 Settings.Secure.BACKUP_ENABLED, null, userId); 398 } else { 399 if (DEBUG) { 400 Slog.i(TAG, "Backup not yet configured; retaining null enable state"); 401 } 402 } 403 } 404 405 try { 406 sInstance.setBackupEnabled(readBackupEnableState(userId)); 407 } catch (RemoteException e) { 408 // can't happen; it's a local object 409 } 410 } 411 } 412 } 413 414 class ProvisionedObserver extends ContentObserver { 415 public ProvisionedObserver(Handler handler) { 416 super(handler); 417 } 418 419 public void onChange(boolean selfChange) { 420 final boolean wasProvisioned = mProvisioned; 421 final boolean isProvisioned = deviceIsProvisioned(); 422 // latch: never unprovision 423 mProvisioned = wasProvisioned || isProvisioned; 424 if (MORE_DEBUG) { 425 Slog.d(TAG, "Provisioning change: was=" + wasProvisioned 426 + " is=" + isProvisioned + " now=" + mProvisioned); 427 } 428 429 synchronized (mQueueLock) { 430 if (mProvisioned && !wasProvisioned && mEnabled) { 431 // we're now good to go, so start the backup alarms 432 if (MORE_DEBUG) Slog.d(TAG, "Now provisioned, so starting backups"); 433 KeyValueBackupJob.schedule(mContext); 434 scheduleNextFullBackupJob(0); 435 } 436 } 437 } 438 } 439 440 class RestoreGetSetsParams { 441 public IBackupTransport transport; 442 public ActiveRestoreSession session; 443 public IRestoreObserver observer; 444 public IBackupManagerMonitor monitor; 445 446 RestoreGetSetsParams(IBackupTransport _transport, ActiveRestoreSession _session, 447 IRestoreObserver _observer, IBackupManagerMonitor _monitor) { 448 transport = _transport; 449 session = _session; 450 observer = _observer; 451 monitor = _monitor; 452 } 453 } 454 455 class RestoreParams { 456 public IBackupTransport transport; 457 public String dirName; 458 public IRestoreObserver observer; 459 public IBackupManagerMonitor monitor; 460 public long token; 461 public PackageInfo pkgInfo; 462 public int pmToken; // in post-install restore, the PM's token for this transaction 463 public boolean isSystemRestore; 464 public String[] filterSet; 465 466 /** 467 * Restore a single package; no kill after restore 468 */ 469 RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs, 470 IBackupManagerMonitor _monitor, long _token, PackageInfo _pkg) { 471 transport = _transport; 472 dirName = _dirName; 473 observer = _obs; 474 monitor = _monitor; 475 token = _token; 476 pkgInfo = _pkg; 477 pmToken = 0; 478 isSystemRestore = false; 479 filterSet = null; 480 } 481 482 /** 483 * Restore at install: PM token needed, kill after restore 484 */ 485 RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs, 486 IBackupManagerMonitor _monitor, long _token, String _pkgName, int _pmToken) { 487 transport = _transport; 488 dirName = _dirName; 489 observer = _obs; 490 monitor = _monitor; 491 token = _token; 492 pkgInfo = null; 493 pmToken = _pmToken; 494 isSystemRestore = false; 495 filterSet = new String[] { _pkgName }; 496 } 497 498 /** 499 * Restore everything possible. This is the form that Setup Wizard or similar 500 * restore UXes use. 501 */ 502 RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs, 503 IBackupManagerMonitor _monitor, long _token) { 504 transport = _transport; 505 dirName = _dirName; 506 observer = _obs; 507 monitor = _monitor; 508 token = _token; 509 pkgInfo = null; 510 pmToken = 0; 511 isSystemRestore = true; 512 filterSet = null; 513 } 514 515 /** 516 * Restore some set of packages. Leave this one up to the caller to specify 517 * whether it's to be considered a system-level restore. 518 */ 519 RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs, 520 IBackupManagerMonitor _monitor, long _token, 521 String[] _filterSet, boolean _isSystemRestore) { 522 transport = _transport; 523 dirName = _dirName; 524 observer = _obs; 525 monitor = _monitor; 526 token = _token; 527 pkgInfo = null; 528 pmToken = 0; 529 isSystemRestore = _isSystemRestore; 530 filterSet = _filterSet; 531 } 532 } 533 534 class ClearParams { 535 public IBackupTransport transport; 536 public PackageInfo packageInfo; 537 538 ClearParams(IBackupTransport _transport, PackageInfo _info) { 539 transport = _transport; 540 packageInfo = _info; 541 } 542 } 543 544 class ClearRetryParams { 545 public String transportName; 546 public String packageName; 547 548 ClearRetryParams(String transport, String pkg) { 549 transportName = transport; 550 packageName = pkg; 551 } 552 } 553 554 class FullParams { 555 public ParcelFileDescriptor fd; 556 public final AtomicBoolean latch; 557 public IFullBackupRestoreObserver observer; 558 public String curPassword; // filled in by the confirmation step 559 public String encryptPassword; 560 561 FullParams() { 562 latch = new AtomicBoolean(false); 563 } 564 } 565 566 class FullBackupParams extends FullParams { 567 public boolean includeApks; 568 public boolean includeObbs; 569 public boolean includeShared; 570 public boolean doWidgets; 571 public boolean allApps; 572 public boolean includeSystem; 573 public boolean doCompress; 574 public String[] packages; 575 576 FullBackupParams(ParcelFileDescriptor output, boolean saveApks, boolean saveObbs, 577 boolean saveShared, boolean alsoWidgets, boolean doAllApps, boolean doSystem, 578 boolean compress, String[] pkgList) { 579 fd = output; 580 includeApks = saveApks; 581 includeObbs = saveObbs; 582 includeShared = saveShared; 583 doWidgets = alsoWidgets; 584 allApps = doAllApps; 585 includeSystem = doSystem; 586 doCompress = compress; 587 packages = pkgList; 588 } 589 } 590 591 class FullRestoreParams extends FullParams { 592 FullRestoreParams(ParcelFileDescriptor input) { 593 fd = input; 594 } 595 } 596 597 class BackupParams { 598 public IBackupTransport transport; 599 public String dirName; 600 public ArrayList<String> kvPackages; 601 public ArrayList<String> fullPackages; 602 public IBackupObserver observer; 603 public IBackupManagerMonitor monitor; 604 public boolean userInitiated; 605 public boolean nonIncrementalBackup; 606 607 BackupParams(IBackupTransport transport, String dirName, ArrayList<String> kvPackages, 608 ArrayList<String> fullPackages, IBackupObserver observer, 609 IBackupManagerMonitor monitor,boolean userInitiated, boolean nonIncrementalBackup) { 610 this.transport = transport; 611 this.dirName = dirName; 612 this.kvPackages = kvPackages; 613 this.fullPackages = fullPackages; 614 this.observer = observer; 615 this.monitor = monitor; 616 this.userInitiated = userInitiated; 617 this.nonIncrementalBackup = nonIncrementalBackup; 618 } 619 } 620 621 // Bookkeeping of in-flight operations for timeout etc. purposes. The operation 622 // token is the index of the entry in the pending-operations list. 623 static final int OP_PENDING = 0; 624 static final int OP_ACKNOWLEDGED = 1; 625 static final int OP_TIMEOUT = -1; 626 627 // Waiting for backup agent to respond during backup operation. 628 private static final int OP_TYPE_BACKUP_WAIT = 0; 629 630 // Waiting for backup agent to respond during restore operation. 631 private static final int OP_TYPE_RESTORE_WAIT = 1; 632 633 // An entire backup operation spanning multiple packages. 634 private static final int OP_TYPE_BACKUP = 2; 635 636 class Operation { 637 int state; 638 final BackupRestoreTask callback; 639 final int type; 640 641 Operation(int initialState, BackupRestoreTask callbackObj, int type) { 642 state = initialState; 643 callback = callbackObj; 644 this.type = type; 645 } 646 } 647 648 /** 649 * mCurrentOperations contains the list of currently active operations. 650 * 651 * If type of operation is OP_TYPE_WAIT, it are waiting for an ack or timeout. 652 * An operation wraps a BackupRestoreTask within it. 653 * It's the responsibility of this task to remove the operation from this array. 654 * 655 * A BackupRestore task gets notified of ack/timeout for the operation via 656 * BackupRestoreTask#handleCancel, BackupRestoreTask#operationComplete and notifyAll called 657 * on the mCurrentOpLock. {@link BackupManagerService#waitUntilOperationComplete(int)} is 658 * used in various places to 'wait' for notifyAll and detect change of pending state of an 659 * operation. So typically, an operation will be removed from this array by: 660 * - BackupRestoreTask#handleCancel and 661 * - BackupRestoreTask#operationComplete OR waitUntilOperationComplete. Do not remove at both 662 * these places because waitUntilOperationComplete relies on the operation being present to 663 * determine its completion status. 664 * 665 * If type of operation is OP_BACKUP, it is a task running backups. It provides a handle to 666 * cancel backup tasks. 667 */ 668 @GuardedBy("mCurrentOpLock") 669 final SparseArray<Operation> mCurrentOperations = new SparseArray<Operation>(); 670 final Object mCurrentOpLock = new Object(); 671 final Random mTokenGenerator = new Random(); 672 673 final SparseArray<FullParams> mFullConfirmations = new SparseArray<FullParams>(); 674 675 // Where we keep our journal files and other bookkeeping 676 File mBaseStateDir; 677 File mDataDir; 678 File mJournalDir; 679 File mJournal; 680 681 // Backup password, if any, and the file where it's saved. What is stored is not the 682 // password text itself; it's the result of a PBKDF2 hash with a randomly chosen (but 683 // persisted) salt. Validation is performed by running the challenge text through the 684 // same PBKDF2 cycle with the persisted salt; if the resulting derived key string matches 685 // the saved hash string, then the challenge text matches the originally supplied 686 // password text. 687 private final SecureRandom mRng = new SecureRandom(); 688 private String mPasswordHash; 689 private File mPasswordHashFile; 690 private int mPasswordVersion; 691 private File mPasswordVersionFile; 692 private byte[] mPasswordSalt; 693 694 // Configuration of PBKDF2 that we use for generating pw hashes and intermediate keys 695 static final int PBKDF2_HASH_ROUNDS = 10000; 696 static final int PBKDF2_KEY_SIZE = 256; // bits 697 static final int PBKDF2_SALT_SIZE = 512; // bits 698 static final String ENCRYPTION_ALGORITHM_NAME = "AES-256"; 699 700 // Keep a log of all the apps we've ever backed up, and what the 701 // dataset tokens are for both the current backup dataset and 702 // the ancestral dataset. 703 private File mEverStored; 704 HashSet<String> mEverStoredApps = new HashSet<String>(); 705 706 static final int CURRENT_ANCESTRAL_RECORD_VERSION = 1; // increment when the schema changes 707 File mTokenFile; 708 Set<String> mAncestralPackages = null; 709 long mAncestralToken = 0; 710 long mCurrentToken = 0; 711 712 // Persistently track the need to do a full init 713 static final String INIT_SENTINEL_FILE_NAME = "_need_init_"; 714 HashSet<String> mPendingInits = new HashSet<String>(); // transport names 715 716 // Round-robin queue for scheduling full backup passes 717 static final int SCHEDULE_FILE_VERSION = 1; // current version of the schedule file 718 class FullBackupEntry implements Comparable<FullBackupEntry> { 719 String packageName; 720 long lastBackup; 721 722 FullBackupEntry(String pkg, long when) { 723 packageName = pkg; 724 lastBackup = when; 725 } 726 727 @Override 728 public int compareTo(FullBackupEntry other) { 729 if (lastBackup < other.lastBackup) return -1; 730 else if (lastBackup > other.lastBackup) return 1; 731 else return 0; 732 } 733 } 734 735 File mFullBackupScheduleFile; 736 // If we're running a schedule-driven full backup, this is the task instance doing it 737 738 @GuardedBy("mQueueLock") 739 PerformFullTransportBackupTask mRunningFullBackupTask; 740 741 @GuardedBy("mQueueLock") 742 ArrayList<FullBackupEntry> mFullBackupQueue; 743 744 // Utility: build a new random integer token 745 int generateToken() { 746 int token; 747 do { 748 synchronized (mTokenGenerator) { 749 token = mTokenGenerator.nextInt(); 750 } 751 } while (token < 0); 752 return token; 753 } 754 755 // High level policy: apps are generally ineligible for backup if certain conditions apply 756 public static boolean appIsEligibleForBackup(ApplicationInfo app) { 757 // 1. their manifest states android:allowBackup="false" 758 if ((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) { 759 return false; 760 } 761 762 // 2. they run as a system-level uid but do not supply their own backup agent 763 if ((app.uid < Process.FIRST_APPLICATION_UID) && (app.backupAgentName == null)) { 764 return false; 765 } 766 767 // 3. it is the special shared-storage backup package used for 'adb backup' 768 if (app.packageName.equals(BackupManagerService.SHARED_BACKUP_AGENT_PACKAGE)) { 769 return false; 770 } 771 772 return true; 773 } 774 775 // Checks if the app is in a stopped state, that means it won't receive broadcasts. 776 private static boolean appIsStopped(ApplicationInfo app) { 777 return ((app.flags & ApplicationInfo.FLAG_STOPPED) != 0); 778 } 779 780 /* does *not* check overall backup eligibility policy! */ 781 private static boolean appGetsFullBackup(PackageInfo pkg) { 782 if (pkg.applicationInfo.backupAgentName != null) { 783 // If it has an agent, it gets full backups only if it says so 784 return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_FULL_BACKUP_ONLY) != 0; 785 } 786 787 // No agent or fullBackupOnly="true" means we do indeed perform full-data backups for it 788 return true; 789 } 790 791 /* adb backup: is this app only capable of doing key/value? We say otherwise if 792 * the app has a backup agent and does not say fullBackupOnly, *unless* it 793 * is a package that we know _a priori_ explicitly supports both key/value and 794 * full-data backup. 795 */ 796 private static boolean appIsKeyValueOnly(PackageInfo pkg) { 797 if ("com.android.providers.settings".equals(pkg.packageName)) { 798 return false; 799 } 800 801 return !appGetsFullBackup(pkg); 802 } 803 804 // ----- Asynchronous backup/restore handler thread ----- 805 806 private class BackupHandler extends Handler { 807 public BackupHandler(Looper looper) { 808 super(looper); 809 } 810 811 public void handleMessage(Message msg) { 812 813 switch (msg.what) { 814 case MSG_RUN_BACKUP: 815 { 816 mLastBackupPass = System.currentTimeMillis(); 817 818 IBackupTransport transport = mTransportManager.getCurrentTransportBinder(); 819 if (transport == null) { 820 Slog.v(TAG, "Backup requested but no transport available"); 821 synchronized (mQueueLock) { 822 mBackupRunning = false; 823 } 824 mWakelock.release(); 825 break; 826 } 827 828 // snapshot the pending-backup set and work on that 829 ArrayList<BackupRequest> queue = new ArrayList<BackupRequest>(); 830 File oldJournal = mJournal; 831 synchronized (mQueueLock) { 832 // Do we have any work to do? Construct the work queue 833 // then release the synchronization lock to actually run 834 // the backup. 835 if (mPendingBackups.size() > 0) { 836 for (BackupRequest b: mPendingBackups.values()) { 837 queue.add(b); 838 } 839 if (DEBUG) Slog.v(TAG, "clearing pending backups"); 840 mPendingBackups.clear(); 841 842 // Start a new backup-queue journal file too 843 mJournal = null; 844 845 } 846 } 847 848 // At this point, we have started a new journal file, and the old 849 // file identity is being passed to the backup processing task. 850 // When it completes successfully, that old journal file will be 851 // deleted. If we crash prior to that, the old journal is parsed 852 // at next boot and the journaled requests fulfilled. 853 boolean staged = true; 854 if (queue.size() > 0) { 855 // Spin up a backup state sequence and set it running 856 try { 857 String dirName = transport.transportDirName(); 858 PerformBackupTask pbt = new PerformBackupTask(transport, dirName, queue, 859 oldJournal, null, null, null, false, false /* nonIncremental */); 860 Message pbtMessage = obtainMessage(MSG_BACKUP_RESTORE_STEP, pbt); 861 sendMessage(pbtMessage); 862 } catch (Exception e) { 863 // unable to ask the transport its dir name -- transient failure, since 864 // the above check succeeded. Try again next time. 865 Slog.e(TAG, "Transport became unavailable attempting backup"); 866 staged = false; 867 } 868 } else { 869 Slog.v(TAG, "Backup requested but nothing pending"); 870 staged = false; 871 } 872 873 if (!staged) { 874 // if we didn't actually hand off the wakelock, rewind until next time 875 synchronized (mQueueLock) { 876 mBackupRunning = false; 877 } 878 mWakelock.release(); 879 } 880 break; 881 } 882 883 case MSG_BACKUP_RESTORE_STEP: 884 { 885 try { 886 BackupRestoreTask task = (BackupRestoreTask) msg.obj; 887 if (MORE_DEBUG) Slog.v(TAG, "Got next step for " + task + ", executing"); 888 task.execute(); 889 } catch (ClassCastException e) { 890 Slog.e(TAG, "Invalid backup task in flight, obj=" + msg.obj); 891 } 892 break; 893 } 894 895 case MSG_OP_COMPLETE: 896 { 897 try { 898 Pair<BackupRestoreTask, Long> taskWithResult = 899 (Pair<BackupRestoreTask, Long>) msg.obj; 900 taskWithResult.first.operationComplete(taskWithResult.second); 901 } catch (ClassCastException e) { 902 Slog.e(TAG, "Invalid completion in flight, obj=" + msg.obj); 903 } 904 break; 905 } 906 907 case MSG_RUN_ADB_BACKUP: 908 { 909 // TODO: refactor full backup to be a looper-based state machine 910 // similar to normal backup/restore. 911 FullBackupParams params = (FullBackupParams)msg.obj; 912 PerformAdbBackupTask task = new PerformAdbBackupTask(params.fd, 913 params.observer, params.includeApks, params.includeObbs, 914 params.includeShared, params.doWidgets, 915 params.curPassword, params.encryptPassword, 916 params.allApps, params.includeSystem, params.doCompress, 917 params.packages, params.latch); 918 (new Thread(task, "adb-backup")).start(); 919 break; 920 } 921 922 case MSG_RUN_FULL_TRANSPORT_BACKUP: 923 { 924 PerformFullTransportBackupTask task = (PerformFullTransportBackupTask) msg.obj; 925 (new Thread(task, "transport-backup")).start(); 926 break; 927 } 928 929 case MSG_RUN_RESTORE: 930 { 931 RestoreParams params = (RestoreParams)msg.obj; 932 Slog.d(TAG, "MSG_RUN_RESTORE observer=" + params.observer); 933 934 PerformUnifiedRestoreTask task = new PerformUnifiedRestoreTask(params.transport, 935 params.observer, params.monitor, params.token, params.pkgInfo, 936 params.pmToken, params.isSystemRestore, params.filterSet); 937 938 synchronized (mPendingRestores) { 939 if (mIsRestoreInProgress) { 940 if (DEBUG) { 941 Slog.d(TAG, "Restore in progress, queueing."); 942 } 943 mPendingRestores.add(task); 944 // This task will be picked up and executed when the the currently running 945 // restore task finishes. 946 } else { 947 if (DEBUG) { 948 Slog.d(TAG, "Starting restore."); 949 } 950 mIsRestoreInProgress = true; 951 Message restoreMsg = obtainMessage(MSG_BACKUP_RESTORE_STEP, task); 952 sendMessage(restoreMsg); 953 } 954 } 955 break; 956 } 957 958 case MSG_RUN_ADB_RESTORE: 959 { 960 // TODO: refactor full restore to be a looper-based state machine 961 // similar to normal backup/restore. 962 FullRestoreParams params = (FullRestoreParams)msg.obj; 963 PerformAdbRestoreTask task = new PerformAdbRestoreTask(params.fd, 964 params.curPassword, params.encryptPassword, 965 params.observer, params.latch); 966 (new Thread(task, "adb-restore")).start(); 967 break; 968 } 969 970 case MSG_RUN_CLEAR: 971 { 972 ClearParams params = (ClearParams)msg.obj; 973 (new PerformClearTask(params.transport, params.packageInfo)).run(); 974 break; 975 } 976 977 case MSG_RETRY_CLEAR: 978 { 979 // reenqueues if the transport remains unavailable 980 ClearRetryParams params = (ClearRetryParams)msg.obj; 981 clearBackupData(params.transportName, params.packageName); 982 break; 983 } 984 985 case MSG_RUN_INITIALIZE: 986 { 987 HashSet<String> queue; 988 989 // Snapshot the pending-init queue and work on that 990 synchronized (mQueueLock) { 991 queue = new HashSet<String>(mPendingInits); 992 mPendingInits.clear(); 993 } 994 995 (new PerformInitializeTask(queue)).run(); 996 break; 997 } 998 999 case MSG_RETRY_INIT: 1000 { 1001 synchronized (mQueueLock) { 1002 recordInitPendingLocked(msg.arg1 != 0, (String)msg.obj); 1003 mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1004 mRunInitIntent); 1005 } 1006 break; 1007 } 1008 1009 case MSG_RUN_GET_RESTORE_SETS: 1010 { 1011 // Like other async operations, this is entered with the wakelock held 1012 RestoreSet[] sets = null; 1013 RestoreGetSetsParams params = (RestoreGetSetsParams)msg.obj; 1014 try { 1015 sets = params.transport.getAvailableRestoreSets(); 1016 // cache the result in the active session 1017 synchronized (params.session) { 1018 params.session.mRestoreSets = sets; 1019 } 1020 if (sets == null) EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE); 1021 } catch (Exception e) { 1022 Slog.e(TAG, "Error from transport getting set list: " + e.getMessage()); 1023 } finally { 1024 if (params.observer != null) { 1025 try { 1026 params.observer.restoreSetsAvailable(sets); 1027 } catch (RemoteException re) { 1028 Slog.e(TAG, "Unable to report listing to observer"); 1029 } catch (Exception e) { 1030 Slog.e(TAG, "Restore observer threw: " + e.getMessage()); 1031 } 1032 } 1033 1034 // Done: reset the session timeout clock 1035 removeMessages(MSG_RESTORE_SESSION_TIMEOUT); 1036 sendEmptyMessageDelayed(MSG_RESTORE_SESSION_TIMEOUT, TIMEOUT_RESTORE_INTERVAL); 1037 1038 mWakelock.release(); 1039 } 1040 break; 1041 } 1042 1043 case MSG_BACKUP_OPERATION_TIMEOUT: 1044 case MSG_RESTORE_OPERATION_TIMEOUT: 1045 { 1046 Slog.d(TAG, "Timeout message received for token=" + Integer.toHexString(msg.arg1)); 1047 handleCancel(msg.arg1, false); 1048 break; 1049 } 1050 1051 case MSG_RESTORE_SESSION_TIMEOUT: 1052 { 1053 synchronized (BackupManagerService.this) { 1054 if (mActiveRestoreSession != null) { 1055 // Client app left the restore session dangling. We know that it 1056 // can't be in the middle of an actual restore operation because 1057 // the timeout is suspended while a restore is in progress. Clean 1058 // up now. 1059 Slog.w(TAG, "Restore session timed out; aborting"); 1060 mActiveRestoreSession.markTimedOut(); 1061 post(mActiveRestoreSession.new EndRestoreRunnable( 1062 BackupManagerService.this, mActiveRestoreSession)); 1063 } 1064 } 1065 break; 1066 } 1067 1068 case MSG_FULL_CONFIRMATION_TIMEOUT: 1069 { 1070 synchronized (mFullConfirmations) { 1071 FullParams params = mFullConfirmations.get(msg.arg1); 1072 if (params != null) { 1073 Slog.i(TAG, "Full backup/restore timed out waiting for user confirmation"); 1074 1075 // Release the waiter; timeout == completion 1076 signalFullBackupRestoreCompletion(params); 1077 1078 // Remove the token from the set 1079 mFullConfirmations.delete(msg.arg1); 1080 1081 // Report a timeout to the observer, if any 1082 if (params.observer != null) { 1083 try { 1084 params.observer.onTimeout(); 1085 } catch (RemoteException e) { 1086 /* don't care if the app has gone away */ 1087 } 1088 } 1089 } else { 1090 Slog.d(TAG, "couldn't find params for token " + msg.arg1); 1091 } 1092 } 1093 break; 1094 } 1095 1096 case MSG_WIDGET_BROADCAST: 1097 { 1098 final Intent intent = (Intent) msg.obj; 1099 mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM); 1100 break; 1101 } 1102 1103 case MSG_REQUEST_BACKUP: 1104 { 1105 BackupParams params = (BackupParams)msg.obj; 1106 if (MORE_DEBUG) { 1107 Slog.d(TAG, "MSG_REQUEST_BACKUP observer=" + params.observer); 1108 } 1109 ArrayList<BackupRequest> kvQueue = new ArrayList<>(); 1110 for (String packageName : params.kvPackages) { 1111 kvQueue.add(new BackupRequest(packageName)); 1112 } 1113 mBackupRunning = true; 1114 mWakelock.acquire(); 1115 1116 PerformBackupTask pbt = new PerformBackupTask(params.transport, params.dirName, 1117 kvQueue, null, params.observer, params.monitor, params.fullPackages, true, 1118 params.nonIncrementalBackup); 1119 Message pbtMessage = obtainMessage(MSG_BACKUP_RESTORE_STEP, pbt); 1120 sendMessage(pbtMessage); 1121 break; 1122 } 1123 1124 case MSG_SCHEDULE_BACKUP_PACKAGE: 1125 { 1126 String pkgName = (String)msg.obj; 1127 if (MORE_DEBUG) { 1128 Slog.d(TAG, "MSG_SCHEDULE_BACKUP_PACKAGE " + pkgName); 1129 } 1130 dataChangedImpl(pkgName); 1131 break; 1132 } 1133 } 1134 } 1135 } 1136 1137 // ----- Debug-only backup operation trace ----- 1138 void addBackupTrace(String s) { 1139 if (DEBUG_BACKUP_TRACE) { 1140 synchronized (mBackupTrace) { 1141 mBackupTrace.add(s); 1142 } 1143 } 1144 } 1145 1146 void clearBackupTrace() { 1147 if (DEBUG_BACKUP_TRACE) { 1148 synchronized (mBackupTrace) { 1149 mBackupTrace.clear(); 1150 } 1151 } 1152 } 1153 1154 // ----- Main service implementation ----- 1155 1156 public BackupManagerService(Context context, Trampoline parent) { 1157 mContext = context; 1158 mPackageManager = context.getPackageManager(); 1159 mPackageManagerBinder = AppGlobals.getPackageManager(); 1160 mActivityManager = ActivityManager.getService(); 1161 1162 mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 1163 mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); 1164 mStorageManager = IStorageManager.Stub.asInterface(ServiceManager.getService("mount")); 1165 1166 mBackupManagerBinder = Trampoline.asInterface(parent.asBinder()); 1167 1168 // spin up the backup/restore handler thread 1169 mHandlerThread = new HandlerThread("backup", Process.THREAD_PRIORITY_BACKGROUND); 1170 mHandlerThread.start(); 1171 mBackupHandler = new BackupHandler(mHandlerThread.getLooper()); 1172 1173 // Set up our bookkeeping 1174 final ContentResolver resolver = context.getContentResolver(); 1175 mProvisioned = Settings.Global.getInt(resolver, 1176 Settings.Global.DEVICE_PROVISIONED, 0) != 0; 1177 mAutoRestore = Settings.Secure.getInt(resolver, 1178 Settings.Secure.BACKUP_AUTO_RESTORE, 1) != 0; 1179 1180 mProvisionedObserver = new ProvisionedObserver(mBackupHandler); 1181 resolver.registerContentObserver( 1182 Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), 1183 false, mProvisionedObserver); 1184 1185 // If Encrypted file systems is enabled or disabled, this call will return the 1186 // correct directory. 1187 mBaseStateDir = new File(Environment.getDataDirectory(), "backup"); 1188 mBaseStateDir.mkdirs(); 1189 if (!SELinux.restorecon(mBaseStateDir)) { 1190 Slog.e(TAG, "SELinux restorecon failed on " + mBaseStateDir); 1191 } 1192 1193 // This dir on /cache is managed directly in init.rc 1194 mDataDir = new File(Environment.getDownloadCacheDirectory(), "backup_stage"); 1195 1196 mPasswordVersion = 1; // unless we hear otherwise 1197 mPasswordVersionFile = new File(mBaseStateDir, "pwversion"); 1198 if (mPasswordVersionFile.exists()) { 1199 FileInputStream fin = null; 1200 DataInputStream in = null; 1201 try { 1202 fin = new FileInputStream(mPasswordVersionFile); 1203 in = new DataInputStream(fin); 1204 mPasswordVersion = in.readInt(); 1205 } catch (IOException e) { 1206 Slog.e(TAG, "Unable to read backup pw version"); 1207 } finally { 1208 try { 1209 if (in != null) in.close(); 1210 if (fin != null) fin.close(); 1211 } catch (IOException e) { 1212 Slog.w(TAG, "Error closing pw version files"); 1213 } 1214 } 1215 } 1216 1217 mPasswordHashFile = new File(mBaseStateDir, "pwhash"); 1218 if (mPasswordHashFile.exists()) { 1219 FileInputStream fin = null; 1220 DataInputStream in = null; 1221 try { 1222 fin = new FileInputStream(mPasswordHashFile); 1223 in = new DataInputStream(new BufferedInputStream(fin)); 1224 // integer length of the salt array, followed by the salt, 1225 // then the hex pw hash string 1226 int saltLen = in.readInt(); 1227 byte[] salt = new byte[saltLen]; 1228 in.readFully(salt); 1229 mPasswordHash = in.readUTF(); 1230 mPasswordSalt = salt; 1231 } catch (IOException e) { 1232 Slog.e(TAG, "Unable to read saved backup pw hash"); 1233 } finally { 1234 try { 1235 if (in != null) in.close(); 1236 if (fin != null) fin.close(); 1237 } catch (IOException e) { 1238 Slog.w(TAG, "Unable to close streams"); 1239 } 1240 } 1241 } 1242 1243 // Alarm receivers for scheduled backups & initialization operations 1244 mRunBackupReceiver = new RunBackupReceiver(); 1245 IntentFilter filter = new IntentFilter(); 1246 filter.addAction(RUN_BACKUP_ACTION); 1247 context.registerReceiver(mRunBackupReceiver, filter, 1248 android.Manifest.permission.BACKUP, null); 1249 1250 mRunInitReceiver = new RunInitializeReceiver(); 1251 filter = new IntentFilter(); 1252 filter.addAction(RUN_INITIALIZE_ACTION); 1253 context.registerReceiver(mRunInitReceiver, filter, 1254 android.Manifest.permission.BACKUP, null); 1255 1256 Intent backupIntent = new Intent(RUN_BACKUP_ACTION); 1257 backupIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 1258 mRunBackupIntent = PendingIntent.getBroadcast(context, MSG_RUN_BACKUP, backupIntent, 0); 1259 1260 Intent initIntent = new Intent(RUN_INITIALIZE_ACTION); 1261 backupIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 1262 mRunInitIntent = PendingIntent.getBroadcast(context, MSG_RUN_INITIALIZE, initIntent, 0); 1263 1264 // Set up the backup-request journaling 1265 mJournalDir = new File(mBaseStateDir, "pending"); 1266 mJournalDir.mkdirs(); // creates mBaseStateDir along the way 1267 mJournal = null; // will be created on first use 1268 1269 // Set up the various sorts of package tracking we do 1270 mFullBackupScheduleFile = new File(mBaseStateDir, "fb-schedule"); 1271 initPackageTracking(); 1272 1273 // Build our mapping of uid to backup client services. This implicitly 1274 // schedules a backup pass on the Package Manager metadata the first 1275 // time anything needs to be backed up. 1276 synchronized (mBackupParticipants) { 1277 addPackageParticipantsLocked(null); 1278 } 1279 1280 // Set up our transport options and initialize the default transport 1281 // TODO: Don't create transports that we don't need to? 1282 SystemConfig systemConfig = SystemConfig.getInstance(); 1283 Set<ComponentName> transportWhitelist = systemConfig.getBackupTransportWhitelist(); 1284 1285 String transport = Settings.Secure.getString(context.getContentResolver(), 1286 Settings.Secure.BACKUP_TRANSPORT); 1287 if (TextUtils.isEmpty(transport)) { 1288 transport = null; 1289 } 1290 String currentTransport = transport; 1291 if (DEBUG) Slog.v(TAG, "Starting with transport " + currentTransport); 1292 1293 mTransportManager = new TransportManager(context, transportWhitelist, currentTransport, 1294 mTransportBoundListener); 1295 mTransportManager.registerAllTransports(); 1296 1297 // Now that we know about valid backup participants, parse any 1298 // leftover journal files into the pending backup set 1299 mBackupHandler.post(() -> parseLeftoverJournals()); 1300 1301 // Power management 1302 mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*"); 1303 } 1304 1305 private class RunBackupReceiver extends BroadcastReceiver { 1306 public void onReceive(Context context, Intent intent) { 1307 if (RUN_BACKUP_ACTION.equals(intent.getAction())) { 1308 synchronized (mQueueLock) { 1309 if (mPendingInits.size() > 0) { 1310 // If there are pending init operations, we process those 1311 // and then settle into the usual periodic backup schedule. 1312 if (MORE_DEBUG) Slog.v(TAG, "Init pending at scheduled backup"); 1313 try { 1314 mAlarmManager.cancel(mRunInitIntent); 1315 mRunInitIntent.send(); 1316 } catch (PendingIntent.CanceledException ce) { 1317 Slog.e(TAG, "Run init intent cancelled"); 1318 // can't really do more than bail here 1319 } 1320 } else { 1321 // Don't run backups now if we're disabled or not yet 1322 // fully set up. 1323 if (mEnabled && mProvisioned) { 1324 if (!mBackupRunning) { 1325 if (DEBUG) Slog.v(TAG, "Running a backup pass"); 1326 1327 // Acquire the wakelock and pass it to the backup thread. it will 1328 // be released once backup concludes. 1329 mBackupRunning = true; 1330 mWakelock.acquire(); 1331 1332 Message msg = mBackupHandler.obtainMessage(MSG_RUN_BACKUP); 1333 mBackupHandler.sendMessage(msg); 1334 } else { 1335 Slog.i(TAG, "Backup time but one already running"); 1336 } 1337 } else { 1338 Slog.w(TAG, "Backup pass but e=" + mEnabled + " p=" + mProvisioned); 1339 } 1340 } 1341 } 1342 } 1343 } 1344 } 1345 1346 private class RunInitializeReceiver extends BroadcastReceiver { 1347 public void onReceive(Context context, Intent intent) { 1348 if (RUN_INITIALIZE_ACTION.equals(intent.getAction())) { 1349 synchronized (mQueueLock) { 1350 if (DEBUG) Slog.v(TAG, "Running a device init"); 1351 1352 // Acquire the wakelock and pass it to the init thread. it will 1353 // be released once init concludes. 1354 mWakelock.acquire(); 1355 1356 Message msg = mBackupHandler.obtainMessage(MSG_RUN_INITIALIZE); 1357 mBackupHandler.sendMessage(msg); 1358 } 1359 } 1360 } 1361 } 1362 1363 private void initPackageTracking() { 1364 if (MORE_DEBUG) Slog.v(TAG, "` tracking"); 1365 1366 // Remember our ancestral dataset 1367 mTokenFile = new File(mBaseStateDir, "ancestral"); 1368 try { 1369 RandomAccessFile tf = new RandomAccessFile(mTokenFile, "r"); 1370 int version = tf.readInt(); 1371 if (version == CURRENT_ANCESTRAL_RECORD_VERSION) { 1372 mAncestralToken = tf.readLong(); 1373 mCurrentToken = tf.readLong(); 1374 1375 int numPackages = tf.readInt(); 1376 if (numPackages >= 0) { 1377 mAncestralPackages = new HashSet<String>(); 1378 for (int i = 0; i < numPackages; i++) { 1379 String pkgName = tf.readUTF(); 1380 mAncestralPackages.add(pkgName); 1381 } 1382 } 1383 } 1384 tf.close(); 1385 } catch (FileNotFoundException fnf) { 1386 // Probably innocuous 1387 Slog.v(TAG, "No ancestral data"); 1388 } catch (IOException e) { 1389 Slog.w(TAG, "Unable to read token file", e); 1390 } 1391 1392 // Keep a log of what apps we've ever backed up. Because we might have 1393 // rebooted in the middle of an operation that was removing something from 1394 // this log, we sanity-check its contents here and reconstruct it. 1395 mEverStored = new File(mBaseStateDir, "processed"); 1396 File tempProcessedFile = new File(mBaseStateDir, "processed.new"); 1397 1398 // If we were in the middle of removing something from the ever-backed-up 1399 // file, there might be a transient "processed.new" file still present. 1400 // Ignore it -- we'll validate "processed" against the current package set. 1401 if (tempProcessedFile.exists()) { 1402 tempProcessedFile.delete(); 1403 } 1404 1405 // If there are previous contents, parse them out then start a new 1406 // file to continue the recordkeeping. 1407 if (mEverStored.exists()) { 1408 RandomAccessFile temp = null; 1409 RandomAccessFile in = null; 1410 1411 try { 1412 temp = new RandomAccessFile(tempProcessedFile, "rws"); 1413 in = new RandomAccessFile(mEverStored, "r"); 1414 1415 // Loop until we hit EOF 1416 while (true) { 1417 String pkg = in.readUTF(); 1418 try { 1419 // is this package still present? 1420 mPackageManager.getPackageInfo(pkg, 0); 1421 // if we get here then yes it is; remember it 1422 mEverStoredApps.add(pkg); 1423 temp.writeUTF(pkg); 1424 if (MORE_DEBUG) Slog.v(TAG, " + " + pkg); 1425 } catch (NameNotFoundException e) { 1426 // nope, this package was uninstalled; don't include it 1427 if (MORE_DEBUG) Slog.v(TAG, " - " + pkg); 1428 } 1429 } 1430 } catch (EOFException e) { 1431 // Once we've rewritten the backup history log, atomically replace the 1432 // old one with the new one then reopen the file for continuing use. 1433 if (!tempProcessedFile.renameTo(mEverStored)) { 1434 Slog.e(TAG, "Error renaming " + tempProcessedFile + " to " + mEverStored); 1435 } 1436 } catch (IOException e) { 1437 Slog.e(TAG, "Error in processed file", e); 1438 } finally { 1439 try { if (temp != null) temp.close(); } catch (IOException e) {} 1440 try { if (in != null) in.close(); } catch (IOException e) {} 1441 } 1442 } 1443 1444 synchronized (mQueueLock) { 1445 // Resume the full-data backup queue 1446 mFullBackupQueue = readFullBackupSchedule(); 1447 } 1448 1449 // Register for broadcasts about package install, etc., so we can 1450 // update the provider list. 1451 IntentFilter filter = new IntentFilter(); 1452 filter.addAction(Intent.ACTION_PACKAGE_ADDED); 1453 filter.addAction(Intent.ACTION_PACKAGE_REMOVED); 1454 filter.addAction(Intent.ACTION_PACKAGE_CHANGED); 1455 filter.addDataScheme("package"); 1456 mContext.registerReceiver(mBroadcastReceiver, filter); 1457 // Register for events related to sdcard installation. 1458 IntentFilter sdFilter = new IntentFilter(); 1459 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); 1460 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); 1461 mContext.registerReceiver(mBroadcastReceiver, sdFilter); 1462 } 1463 1464 private ArrayList<FullBackupEntry> readFullBackupSchedule() { 1465 boolean changed = false; 1466 ArrayList<FullBackupEntry> schedule = null; 1467 List<PackageInfo> apps = 1468 PackageManagerBackupAgent.getStorableApplications(mPackageManager); 1469 1470 if (mFullBackupScheduleFile.exists()) { 1471 FileInputStream fstream = null; 1472 BufferedInputStream bufStream = null; 1473 DataInputStream in = null; 1474 try { 1475 fstream = new FileInputStream(mFullBackupScheduleFile); 1476 bufStream = new BufferedInputStream(fstream); 1477 in = new DataInputStream(bufStream); 1478 1479 int version = in.readInt(); 1480 if (version != SCHEDULE_FILE_VERSION) { 1481 Slog.e(TAG, "Unknown backup schedule version " + version); 1482 return null; 1483 } 1484 1485 final int N = in.readInt(); 1486 schedule = new ArrayList<FullBackupEntry>(N); 1487 1488 // HashSet instead of ArraySet specifically because we want the eventual 1489 // lookups against O(hundreds) of entries to be as fast as possible, and 1490 // we discard the set immediately after the scan so the extra memory 1491 // overhead is transient. 1492 HashSet<String> foundApps = new HashSet<String>(N); 1493 1494 for (int i = 0; i < N; i++) { 1495 String pkgName = in.readUTF(); 1496 long lastBackup = in.readLong(); 1497 foundApps.add(pkgName); // all apps that we've addressed already 1498 try { 1499 PackageInfo pkg = mPackageManager.getPackageInfo(pkgName, 0); 1500 if (appGetsFullBackup(pkg) && appIsEligibleForBackup(pkg.applicationInfo)) { 1501 schedule.add(new FullBackupEntry(pkgName, lastBackup)); 1502 } else { 1503 if (DEBUG) { 1504 Slog.i(TAG, "Package " + pkgName 1505 + " no longer eligible for full backup"); 1506 } 1507 } 1508 } catch (NameNotFoundException e) { 1509 if (DEBUG) { 1510 Slog.i(TAG, "Package " + pkgName 1511 + " not installed; dropping from full backup"); 1512 } 1513 } 1514 } 1515 1516 // New apps can arrive "out of band" via OTA and similar, so we also need to 1517 // scan to make sure that we're tracking all full-backup candidates properly 1518 for (PackageInfo app : apps) { 1519 if (appGetsFullBackup(app) && appIsEligibleForBackup(app.applicationInfo)) { 1520 if (!foundApps.contains(app.packageName)) { 1521 if (MORE_DEBUG) { 1522 Slog.i(TAG, "New full backup app " + app.packageName + " found"); 1523 } 1524 schedule.add(new FullBackupEntry(app.packageName, 0)); 1525 changed = true; 1526 } 1527 } 1528 } 1529 1530 Collections.sort(schedule); 1531 } catch (Exception e) { 1532 Slog.e(TAG, "Unable to read backup schedule", e); 1533 mFullBackupScheduleFile.delete(); 1534 schedule = null; 1535 } finally { 1536 IoUtils.closeQuietly(in); 1537 IoUtils.closeQuietly(bufStream); 1538 IoUtils.closeQuietly(fstream); 1539 } 1540 } 1541 1542 if (schedule == null) { 1543 // no prior queue record, or unable to read it. Set up the queue 1544 // from scratch. 1545 changed = true; 1546 schedule = new ArrayList<FullBackupEntry>(apps.size()); 1547 for (PackageInfo info : apps) { 1548 if (appGetsFullBackup(info) && appIsEligibleForBackup(info.applicationInfo)) { 1549 schedule.add(new FullBackupEntry(info.packageName, 0)); 1550 } 1551 } 1552 } 1553 1554 if (changed) { 1555 writeFullBackupScheduleAsync(); 1556 } 1557 return schedule; 1558 } 1559 1560 Runnable mFullBackupScheduleWriter = new Runnable() { 1561 @Override public void run() { 1562 synchronized (mQueueLock) { 1563 try { 1564 ByteArrayOutputStream bufStream = new ByteArrayOutputStream(4096); 1565 DataOutputStream bufOut = new DataOutputStream(bufStream); 1566 bufOut.writeInt(SCHEDULE_FILE_VERSION); 1567 1568 // version 1: 1569 // 1570 // [int] # of packages in the queue = N 1571 // N * { 1572 // [utf8] package name 1573 // [long] last backup time for this package 1574 // } 1575 int N = mFullBackupQueue.size(); 1576 bufOut.writeInt(N); 1577 1578 for (int i = 0; i < N; i++) { 1579 FullBackupEntry entry = mFullBackupQueue.get(i); 1580 bufOut.writeUTF(entry.packageName); 1581 bufOut.writeLong(entry.lastBackup); 1582 } 1583 bufOut.flush(); 1584 1585 AtomicFile af = new AtomicFile(mFullBackupScheduleFile); 1586 FileOutputStream out = af.startWrite(); 1587 out.write(bufStream.toByteArray()); 1588 af.finishWrite(out); 1589 } catch (Exception e) { 1590 Slog.e(TAG, "Unable to write backup schedule!", e); 1591 } 1592 } 1593 } 1594 }; 1595 1596 private void writeFullBackupScheduleAsync() { 1597 mBackupHandler.removeCallbacks(mFullBackupScheduleWriter); 1598 mBackupHandler.post(mFullBackupScheduleWriter); 1599 } 1600 1601 private void parseLeftoverJournals() { 1602 for (File f : mJournalDir.listFiles()) { 1603 if (mJournal == null || f.compareTo(mJournal) != 0) { 1604 // This isn't the current journal, so it must be a leftover. Read 1605 // out the package names mentioned there and schedule them for 1606 // backup. 1607 DataInputStream in = null; 1608 try { 1609 Slog.i(TAG, "Found stale backup journal, scheduling"); 1610 // Journals will tend to be on the order of a few kilobytes(around 4k), hence, 1611 // setting the buffer size to 8192. 1612 InputStream bufferedInputStream = new BufferedInputStream( 1613 new FileInputStream(f), 8192); 1614 in = new DataInputStream(bufferedInputStream); 1615 while (true) { 1616 String packageName = in.readUTF(); 1617 if (MORE_DEBUG) Slog.i(TAG, " " + packageName); 1618 dataChangedImpl(packageName); 1619 } 1620 } catch (EOFException e) { 1621 // no more data; we're done 1622 } catch (Exception e) { 1623 Slog.e(TAG, "Can't read " + f, e); 1624 } finally { 1625 // close/delete the file 1626 try { if (in != null) in.close(); } catch (IOException e) {} 1627 f.delete(); 1628 } 1629 } 1630 } 1631 } 1632 1633 private SecretKey buildPasswordKey(String algorithm, String pw, byte[] salt, int rounds) { 1634 return buildCharArrayKey(algorithm, pw.toCharArray(), salt, rounds); 1635 } 1636 1637 private SecretKey buildCharArrayKey(String algorithm, char[] pwArray, byte[] salt, int rounds) { 1638 try { 1639 SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm); 1640 KeySpec ks = new PBEKeySpec(pwArray, salt, rounds, PBKDF2_KEY_SIZE); 1641 return keyFactory.generateSecret(ks); 1642 } catch (InvalidKeySpecException e) { 1643 Slog.e(TAG, "Invalid key spec for PBKDF2!"); 1644 } catch (NoSuchAlgorithmException e) { 1645 Slog.e(TAG, "PBKDF2 unavailable!"); 1646 } 1647 return null; 1648 } 1649 1650 private String buildPasswordHash(String algorithm, String pw, byte[] salt, int rounds) { 1651 SecretKey key = buildPasswordKey(algorithm, pw, salt, rounds); 1652 if (key != null) { 1653 return byteArrayToHex(key.getEncoded()); 1654 } 1655 return null; 1656 } 1657 1658 private String byteArrayToHex(byte[] data) { 1659 StringBuilder buf = new StringBuilder(data.length * 2); 1660 for (int i = 0; i < data.length; i++) { 1661 buf.append(Byte.toHexString(data[i], true)); 1662 } 1663 return buf.toString(); 1664 } 1665 1666 private byte[] hexToByteArray(String digits) { 1667 final int bytes = digits.length() / 2; 1668 if (2*bytes != digits.length()) { 1669 throw new IllegalArgumentException("Hex string must have an even number of digits"); 1670 } 1671 1672 byte[] result = new byte[bytes]; 1673 for (int i = 0; i < digits.length(); i += 2) { 1674 result[i/2] = (byte) Integer.parseInt(digits.substring(i, i+2), 16); 1675 } 1676 return result; 1677 } 1678 1679 private byte[] makeKeyChecksum(String algorithm, byte[] pwBytes, byte[] salt, int rounds) { 1680 char[] mkAsChar = new char[pwBytes.length]; 1681 for (int i = 0; i < pwBytes.length; i++) { 1682 mkAsChar[i] = (char) pwBytes[i]; 1683 } 1684 1685 Key checksum = buildCharArrayKey(algorithm, mkAsChar, salt, rounds); 1686 return checksum.getEncoded(); 1687 } 1688 1689 // Used for generating random salts or passwords 1690 private byte[] randomBytes(int bits) { 1691 byte[] array = new byte[bits / 8]; 1692 mRng.nextBytes(array); 1693 return array; 1694 } 1695 1696 boolean passwordMatchesSaved(String algorithm, String candidatePw, int rounds) { 1697 if (mPasswordHash == null) { 1698 // no current password case -- require that 'currentPw' be null or empty 1699 if (candidatePw == null || "".equals(candidatePw)) { 1700 return true; 1701 } // else the non-empty candidate does not match the empty stored pw 1702 } else { 1703 // hash the stated current pw and compare to the stored one 1704 if (candidatePw != null && candidatePw.length() > 0) { 1705 String currentPwHash = buildPasswordHash(algorithm, candidatePw, mPasswordSalt, rounds); 1706 if (mPasswordHash.equalsIgnoreCase(currentPwHash)) { 1707 // candidate hash matches the stored hash -- the password matches 1708 return true; 1709 } 1710 } // else the stored pw is nonempty but the candidate is empty; no match 1711 } 1712 return false; 1713 } 1714 1715 public boolean setBackupPassword(String currentPw, String newPw) { 1716 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, 1717 "setBackupPassword"); 1718 1719 // When processing v1 passwords we may need to try two different PBKDF2 checksum regimes 1720 final boolean pbkdf2Fallback = (mPasswordVersion < BACKUP_PW_FILE_VERSION); 1721 1722 // If the supplied pw doesn't hash to the the saved one, fail. The password 1723 // might be caught in the legacy crypto mismatch; verify that too. 1724 if (!passwordMatchesSaved(PBKDF_CURRENT, currentPw, PBKDF2_HASH_ROUNDS) 1725 && !(pbkdf2Fallback && passwordMatchesSaved(PBKDF_FALLBACK, 1726 currentPw, PBKDF2_HASH_ROUNDS))) { 1727 return false; 1728 } 1729 1730 // Snap up to current on the pw file version 1731 mPasswordVersion = BACKUP_PW_FILE_VERSION; 1732 FileOutputStream pwFout = null; 1733 DataOutputStream pwOut = null; 1734 try { 1735 pwFout = new FileOutputStream(mPasswordVersionFile); 1736 pwOut = new DataOutputStream(pwFout); 1737 pwOut.writeInt(mPasswordVersion); 1738 } catch (IOException e) { 1739 Slog.e(TAG, "Unable to write backup pw version; password not changed"); 1740 return false; 1741 } finally { 1742 try { 1743 if (pwOut != null) pwOut.close(); 1744 if (pwFout != null) pwFout.close(); 1745 } catch (IOException e) { 1746 Slog.w(TAG, "Unable to close pw version record"); 1747 } 1748 } 1749 1750 // Clearing the password is okay 1751 if (newPw == null || newPw.isEmpty()) { 1752 if (mPasswordHashFile.exists()) { 1753 if (!mPasswordHashFile.delete()) { 1754 // Unable to delete the old pw file, so fail 1755 Slog.e(TAG, "Unable to clear backup password"); 1756 return false; 1757 } 1758 } 1759 mPasswordHash = null; 1760 mPasswordSalt = null; 1761 return true; 1762 } 1763 1764 try { 1765 // Okay, build the hash of the new backup password 1766 byte[] salt = randomBytes(PBKDF2_SALT_SIZE); 1767 String newPwHash = buildPasswordHash(PBKDF_CURRENT, newPw, salt, PBKDF2_HASH_ROUNDS); 1768 1769 OutputStream pwf = null, buffer = null; 1770 DataOutputStream out = null; 1771 try { 1772 pwf = new FileOutputStream(mPasswordHashFile); 1773 buffer = new BufferedOutputStream(pwf); 1774 out = new DataOutputStream(buffer); 1775 // integer length of the salt array, followed by the salt, 1776 // then the hex pw hash string 1777 out.writeInt(salt.length); 1778 out.write(salt); 1779 out.writeUTF(newPwHash); 1780 out.flush(); 1781 mPasswordHash = newPwHash; 1782 mPasswordSalt = salt; 1783 return true; 1784 } finally { 1785 if (out != null) out.close(); 1786 if (buffer != null) buffer.close(); 1787 if (pwf != null) pwf.close(); 1788 } 1789 } catch (IOException e) { 1790 Slog.e(TAG, "Unable to set backup password"); 1791 } 1792 return false; 1793 } 1794 1795 public boolean hasBackupPassword() { 1796 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, 1797 "hasBackupPassword"); 1798 1799 return mPasswordHash != null && mPasswordHash.length() > 0; 1800 } 1801 1802 private boolean backupPasswordMatches(String currentPw) { 1803 if (hasBackupPassword()) { 1804 final boolean pbkdf2Fallback = (mPasswordVersion < BACKUP_PW_FILE_VERSION); 1805 if (!passwordMatchesSaved(PBKDF_CURRENT, currentPw, PBKDF2_HASH_ROUNDS) 1806 && !(pbkdf2Fallback && passwordMatchesSaved(PBKDF_FALLBACK, 1807 currentPw, PBKDF2_HASH_ROUNDS))) { 1808 if (DEBUG) Slog.w(TAG, "Backup password mismatch; aborting"); 1809 return false; 1810 } 1811 } 1812 return true; 1813 } 1814 1815 // Maintain persistent state around whether need to do an initialize operation. 1816 // Must be called with the queue lock held. 1817 void recordInitPendingLocked(boolean isPending, String transportName) { 1818 if (MORE_DEBUG) Slog.i(TAG, "recordInitPendingLocked: " + isPending 1819 + " on transport " + transportName); 1820 mBackupHandler.removeMessages(MSG_RETRY_INIT); 1821 1822 try { 1823 IBackupTransport transport = mTransportManager.getTransportBinder(transportName); 1824 if (transport != null) { 1825 String transportDirName = transport.transportDirName(); 1826 File stateDir = new File(mBaseStateDir, transportDirName); 1827 File initPendingFile = new File(stateDir, INIT_SENTINEL_FILE_NAME); 1828 1829 if (isPending) { 1830 // We need an init before we can proceed with sending backup data. 1831 // Record that with an entry in our set of pending inits, as well as 1832 // journaling it via creation of a sentinel file. 1833 mPendingInits.add(transportName); 1834 try { 1835 (new FileOutputStream(initPendingFile)).close(); 1836 } catch (IOException ioe) { 1837 // Something is badly wrong with our permissions; just try to move on 1838 } 1839 } else { 1840 // No more initialization needed; wipe the journal and reset our state. 1841 initPendingFile.delete(); 1842 mPendingInits.remove(transportName); 1843 } 1844 return; // done; don't fall through to the error case 1845 } 1846 } catch (Exception e) { 1847 // transport threw when asked its name; fall through to the lookup-failed case 1848 Slog.e(TAG, "Transport " + transportName + " failed to report name: " 1849 + e.getMessage()); 1850 } 1851 1852 // The named transport doesn't exist or threw. This operation is 1853 // important, so we record the need for a an init and post a message 1854 // to retry the init later. 1855 if (isPending) { 1856 mPendingInits.add(transportName); 1857 mBackupHandler.sendMessageDelayed( 1858 mBackupHandler.obtainMessage(MSG_RETRY_INIT, 1859 (isPending ? 1 : 0), 1860 0, 1861 transportName), 1862 TRANSPORT_RETRY_INTERVAL); 1863 } 1864 } 1865 1866 // Reset all of our bookkeeping, in response to having been told that 1867 // the backend data has been wiped [due to idle expiry, for example], 1868 // so we must re-upload all saved settings. 1869 void resetBackupState(File stateFileDir) { 1870 synchronized (mQueueLock) { 1871 // Wipe the "what we've ever backed up" tracking 1872 mEverStoredApps.clear(); 1873 mEverStored.delete(); 1874 1875 mCurrentToken = 0; 1876 writeRestoreTokens(); 1877 1878 // Remove all the state files 1879 for (File sf : stateFileDir.listFiles()) { 1880 // ... but don't touch the needs-init sentinel 1881 if (!sf.getName().equals(INIT_SENTINEL_FILE_NAME)) { 1882 sf.delete(); 1883 } 1884 } 1885 } 1886 1887 // Enqueue a new backup of every participant 1888 synchronized (mBackupParticipants) { 1889 final int N = mBackupParticipants.size(); 1890 for (int i=0; i<N; i++) { 1891 HashSet<String> participants = mBackupParticipants.valueAt(i); 1892 if (participants != null) { 1893 for (String packageName : participants) { 1894 dataChangedImpl(packageName); 1895 } 1896 } 1897 } 1898 } 1899 } 1900 1901 private TransportManager.TransportBoundListener mTransportBoundListener = 1902 new TransportManager.TransportBoundListener() { 1903 @Override 1904 public boolean onTransportBound(IBackupTransport transport) { 1905 // If the init sentinel file exists, we need to be sure to perform the init 1906 // as soon as practical. We also create the state directory at registration 1907 // time to ensure it's present from the outset. 1908 String name = null; 1909 try { 1910 name = transport.name(); 1911 String transportDirName = transport.transportDirName(); 1912 File stateDir = new File(mBaseStateDir, transportDirName); 1913 stateDir.mkdirs(); 1914 1915 File initSentinel = new File(stateDir, INIT_SENTINEL_FILE_NAME); 1916 if (initSentinel.exists()) { 1917 synchronized (mQueueLock) { 1918 mPendingInits.add(name); 1919 1920 // TODO: pick a better starting time than now + 1 minute 1921 long delay = 1000 * 60; // one minute, in milliseconds 1922 mAlarmManager.set(AlarmManager.RTC_WAKEUP, 1923 System.currentTimeMillis() + delay, mRunInitIntent); 1924 } 1925 } 1926 return true; 1927 } catch (Exception e) { 1928 // the transport threw when asked its file naming prefs; declare it invalid 1929 Slog.w(TAG, "Failed to regiser transport: " + name); 1930 return false; 1931 } 1932 } 1933 }; 1934 1935 // ----- Track installation/removal of packages ----- 1936 BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 1937 public void onReceive(Context context, Intent intent) { 1938 if (MORE_DEBUG) Slog.d(TAG, "Received broadcast " + intent); 1939 1940 String action = intent.getAction(); 1941 boolean replacing = false; 1942 boolean added = false; 1943 boolean changed = false; 1944 Bundle extras = intent.getExtras(); 1945 String pkgList[] = null; 1946 if (Intent.ACTION_PACKAGE_ADDED.equals(action) || 1947 Intent.ACTION_PACKAGE_REMOVED.equals(action) || 1948 Intent.ACTION_PACKAGE_CHANGED.equals(action)) { 1949 Uri uri = intent.getData(); 1950 if (uri == null) { 1951 return; 1952 } 1953 String pkgName = uri.getSchemeSpecificPart(); 1954 if (pkgName != null) { 1955 pkgList = new String[] { pkgName }; 1956 } 1957 changed = Intent.ACTION_PACKAGE_CHANGED.equals(action); 1958 1959 // At package-changed we only care about looking at new transport states 1960 if (changed) { 1961 String[] components = 1962 intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST); 1963 1964 if (MORE_DEBUG) { 1965 Slog.i(TAG, "Package " + pkgName + " changed; rechecking"); 1966 for (int i = 0; i < components.length; i++) { 1967 Slog.i(TAG, " * " + components[i]); 1968 } 1969 } 1970 1971 mTransportManager.onPackageChanged(pkgName, components); 1972 return; // nothing more to do in the PACKAGE_CHANGED case 1973 } 1974 1975 added = Intent.ACTION_PACKAGE_ADDED.equals(action); 1976 replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false); 1977 } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) { 1978 added = true; 1979 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 1980 } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { 1981 added = false; 1982 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 1983 } 1984 1985 if (pkgList == null || pkgList.length == 0) { 1986 return; 1987 } 1988 1989 final int uid = extras.getInt(Intent.EXTRA_UID); 1990 if (added) { 1991 synchronized (mBackupParticipants) { 1992 if (replacing) { 1993 // This is the package-replaced case; we just remove the entry 1994 // under the old uid and fall through to re-add. If an app 1995 // just added key/value backup participation, this picks it up 1996 // as a known participant. 1997 removePackageParticipantsLocked(pkgList, uid); 1998 } 1999 addPackageParticipantsLocked(pkgList); 2000 } 2001 // If they're full-backup candidates, add them there instead 2002 final long now = System.currentTimeMillis(); 2003 for (String packageName : pkgList) { 2004 try { 2005 PackageInfo app = mPackageManager.getPackageInfo(packageName, 0); 2006 if (appGetsFullBackup(app) && appIsEligibleForBackup(app.applicationInfo)) { 2007 enqueueFullBackup(packageName, now); 2008 scheduleNextFullBackupJob(0); 2009 } else { 2010 // The app might have just transitioned out of full-data into 2011 // doing key/value backups, or might have just disabled backups 2012 // entirely. Make sure it is no longer in the full-data queue. 2013 synchronized (mQueueLock) { 2014 dequeueFullBackupLocked(packageName); 2015 } 2016 writeFullBackupScheduleAsync(); 2017 } 2018 2019 mTransportManager.onPackageAdded(packageName); 2020 2021 } catch (NameNotFoundException e) { 2022 // doesn't really exist; ignore it 2023 if (DEBUG) { 2024 Slog.w(TAG, "Can't resolve new app " + packageName); 2025 } 2026 } 2027 } 2028 2029 // Whenever a package is added or updated we need to update 2030 // the package metadata bookkeeping. 2031 dataChangedImpl(PACKAGE_MANAGER_SENTINEL); 2032 } else { 2033 if (replacing) { 2034 // The package is being updated. We'll receive a PACKAGE_ADDED shortly. 2035 } else { 2036 // Outright removal. In the full-data case, the app will be dropped 2037 // from the queue when its (now obsolete) name comes up again for 2038 // backup. 2039 synchronized (mBackupParticipants) { 2040 removePackageParticipantsLocked(pkgList, uid); 2041 } 2042 } 2043 for (String pkgName : pkgList) { 2044 mTransportManager.onPackageRemoved(pkgName); 2045 } 2046 } 2047 } 2048 }; 2049 2050 // Add the backup agents in the given packages to our set of known backup participants. 2051 // If 'packageNames' is null, adds all backup agents in the whole system. 2052 void addPackageParticipantsLocked(String[] packageNames) { 2053 // Look for apps that define the android:backupAgent attribute 2054 List<PackageInfo> targetApps = allAgentPackages(); 2055 if (packageNames != null) { 2056 if (MORE_DEBUG) Slog.v(TAG, "addPackageParticipantsLocked: #" + packageNames.length); 2057 for (String packageName : packageNames) { 2058 addPackageParticipantsLockedInner(packageName, targetApps); 2059 } 2060 } else { 2061 if (MORE_DEBUG) Slog.v(TAG, "addPackageParticipantsLocked: all"); 2062 addPackageParticipantsLockedInner(null, targetApps); 2063 } 2064 } 2065 2066 private void addPackageParticipantsLockedInner(String packageName, 2067 List<PackageInfo> targetPkgs) { 2068 if (MORE_DEBUG) { 2069 Slog.v(TAG, "Examining " + packageName + " for backup agent"); 2070 } 2071 2072 for (PackageInfo pkg : targetPkgs) { 2073 if (packageName == null || pkg.packageName.equals(packageName)) { 2074 int uid = pkg.applicationInfo.uid; 2075 HashSet<String> set = mBackupParticipants.get(uid); 2076 if (set == null) { 2077 set = new HashSet<>(); 2078 mBackupParticipants.put(uid, set); 2079 } 2080 set.add(pkg.packageName); 2081 if (MORE_DEBUG) Slog.v(TAG, "Agent found; added"); 2082 2083 // Schedule a backup for it on general principles 2084 if (MORE_DEBUG) Slog.i(TAG, "Scheduling backup for new app " + pkg.packageName); 2085 Message msg = mBackupHandler 2086 .obtainMessage(MSG_SCHEDULE_BACKUP_PACKAGE, pkg.packageName); 2087 mBackupHandler.sendMessage(msg); 2088 } 2089 } 2090 } 2091 2092 // Remove the given packages' entries from our known active set. 2093 void removePackageParticipantsLocked(String[] packageNames, int oldUid) { 2094 if (packageNames == null) { 2095 Slog.w(TAG, "removePackageParticipants with null list"); 2096 return; 2097 } 2098 2099 if (MORE_DEBUG) Slog.v(TAG, "removePackageParticipantsLocked: uid=" + oldUid 2100 + " #" + packageNames.length); 2101 for (String pkg : packageNames) { 2102 // Known previous UID, so we know which package set to check 2103 HashSet<String> set = mBackupParticipants.get(oldUid); 2104 if (set != null && set.contains(pkg)) { 2105 removePackageFromSetLocked(set, pkg); 2106 if (set.isEmpty()) { 2107 if (MORE_DEBUG) Slog.v(TAG, " last one of this uid; purging set"); 2108 mBackupParticipants.remove(oldUid); 2109 } 2110 } 2111 } 2112 } 2113 2114 private void removePackageFromSetLocked(final HashSet<String> set, 2115 final String packageName) { 2116 if (set.contains(packageName)) { 2117 // Found it. Remove this one package from the bookkeeping, and 2118 // if it's the last participating app under this uid we drop the 2119 // (now-empty) set as well. 2120 // Note that we deliberately leave it 'known' in the "ever backed up" 2121 // bookkeeping so that its current-dataset data will be retrieved 2122 // if the app is subsequently reinstalled 2123 if (MORE_DEBUG) Slog.v(TAG, " removing participant " + packageName); 2124 set.remove(packageName); 2125 mPendingBackups.remove(packageName); 2126 } 2127 } 2128 2129 // Returns the set of all applications that define an android:backupAgent attribute 2130 List<PackageInfo> allAgentPackages() { 2131 // !!! TODO: cache this and regenerate only when necessary 2132 int flags = PackageManager.GET_SIGNATURES; 2133 List<PackageInfo> packages = mPackageManager.getInstalledPackages(flags); 2134 int N = packages.size(); 2135 for (int a = N-1; a >= 0; a--) { 2136 PackageInfo pkg = packages.get(a); 2137 try { 2138 ApplicationInfo app = pkg.applicationInfo; 2139 if (((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) 2140 || app.backupAgentName == null 2141 || (app.flags&ApplicationInfo.FLAG_FULL_BACKUP_ONLY) != 0) { 2142 packages.remove(a); 2143 } 2144 else { 2145 // we will need the shared library path, so look that up and store it here. 2146 // This is used implicitly when we pass the PackageInfo object off to 2147 // the Activity Manager to launch the app for backup/restore purposes. 2148 app = mPackageManager.getApplicationInfo(pkg.packageName, 2149 PackageManager.GET_SHARED_LIBRARY_FILES); 2150 pkg.applicationInfo.sharedLibraryFiles = app.sharedLibraryFiles; 2151 } 2152 } catch (NameNotFoundException e) { 2153 packages.remove(a); 2154 } 2155 } 2156 return packages; 2157 } 2158 2159 // Called from the backup tasks: record that the given app has been successfully 2160 // backed up at least once. This includes both key/value and full-data backups 2161 // through the transport. 2162 void logBackupComplete(String packageName) { 2163 if (packageName.equals(PACKAGE_MANAGER_SENTINEL)) return; 2164 2165 synchronized (mEverStoredApps) { 2166 if (!mEverStoredApps.add(packageName)) return; 2167 2168 RandomAccessFile out = null; 2169 try { 2170 out = new RandomAccessFile(mEverStored, "rws"); 2171 out.seek(out.length()); 2172 out.writeUTF(packageName); 2173 } catch (IOException e) { 2174 Slog.e(TAG, "Can't log backup of " + packageName + " to " + mEverStored); 2175 } finally { 2176 try { if (out != null) out.close(); } catch (IOException e) {} 2177 } 2178 } 2179 } 2180 2181 // Remove our awareness of having ever backed up the given package 2182 void removeEverBackedUp(String packageName) { 2183 if (DEBUG) Slog.v(TAG, "Removing backed-up knowledge of " + packageName); 2184 if (MORE_DEBUG) Slog.v(TAG, "New set:"); 2185 2186 synchronized (mEverStoredApps) { 2187 // Rewrite the file and rename to overwrite. If we reboot in the middle, 2188 // we'll recognize on initialization time that the package no longer 2189 // exists and fix it up then. 2190 File tempKnownFile = new File(mBaseStateDir, "processed.new"); 2191 RandomAccessFile known = null; 2192 try { 2193 known = new RandomAccessFile(tempKnownFile, "rws"); 2194 mEverStoredApps.remove(packageName); 2195 for (String s : mEverStoredApps) { 2196 known.writeUTF(s); 2197 if (MORE_DEBUG) Slog.v(TAG, " " + s); 2198 } 2199 known.close(); 2200 known = null; 2201 if (!tempKnownFile.renameTo(mEverStored)) { 2202 throw new IOException("Can't rename " + tempKnownFile + " to " + mEverStored); 2203 } 2204 } catch (IOException e) { 2205 // Bad: we couldn't create the new copy. For safety's sake we 2206 // abandon the whole process and remove all what's-backed-up 2207 // state entirely, meaning we'll force a backup pass for every 2208 // participant on the next boot or [re]install. 2209 Slog.w(TAG, "Error rewriting " + mEverStored, e); 2210 mEverStoredApps.clear(); 2211 tempKnownFile.delete(); 2212 mEverStored.delete(); 2213 } finally { 2214 try { if (known != null) known.close(); } catch (IOException e) {} 2215 } 2216 } 2217 } 2218 2219 // Persistently record the current and ancestral backup tokens as well 2220 // as the set of packages with data [supposedly] available in the 2221 // ancestral dataset. 2222 void writeRestoreTokens() { 2223 try { 2224 RandomAccessFile af = new RandomAccessFile(mTokenFile, "rwd"); 2225 2226 // First, the version number of this record, for futureproofing 2227 af.writeInt(CURRENT_ANCESTRAL_RECORD_VERSION); 2228 2229 // Write the ancestral and current tokens 2230 af.writeLong(mAncestralToken); 2231 af.writeLong(mCurrentToken); 2232 2233 // Now write the set of ancestral packages 2234 if (mAncestralPackages == null) { 2235 af.writeInt(-1); 2236 } else { 2237 af.writeInt(mAncestralPackages.size()); 2238 if (DEBUG) Slog.v(TAG, "Ancestral packages: " + mAncestralPackages.size()); 2239 for (String pkgName : mAncestralPackages) { 2240 af.writeUTF(pkgName); 2241 if (MORE_DEBUG) Slog.v(TAG, " " + pkgName); 2242 } 2243 } 2244 af.close(); 2245 } catch (IOException e) { 2246 Slog.w(TAG, "Unable to write token file:", e); 2247 } 2248 } 2249 2250 // What name is this transport registered under...? 2251 private String getTransportName(IBackupTransport transport) { 2252 if (MORE_DEBUG) { 2253 Slog.v(TAG, "Searching for transport name of " + transport); 2254 } 2255 return mTransportManager.getTransportName(transport); 2256 } 2257 2258 // fire off a backup agent, blocking until it attaches or times out 2259 IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode) { 2260 IBackupAgent agent = null; 2261 synchronized(mAgentConnectLock) { 2262 mConnecting = true; 2263 mConnectedAgent = null; 2264 try { 2265 if (mActivityManager.bindBackupAgent(app.packageName, mode, 2266 UserHandle.USER_OWNER)) { 2267 Slog.d(TAG, "awaiting agent for " + app); 2268 2269 // success; wait for the agent to arrive 2270 // only wait 10 seconds for the bind to happen 2271 long timeoutMark = System.currentTimeMillis() + TIMEOUT_INTERVAL; 2272 while (mConnecting && mConnectedAgent == null 2273 && (System.currentTimeMillis() < timeoutMark)) { 2274 try { 2275 mAgentConnectLock.wait(5000); 2276 } catch (InterruptedException e) { 2277 // just bail 2278 Slog.w(TAG, "Interrupted: " + e); 2279 mConnecting = false; 2280 mConnectedAgent = null; 2281 } 2282 } 2283 2284 // if we timed out with no connect, abort and move on 2285 if (mConnecting == true) { 2286 Slog.w(TAG, "Timeout waiting for agent " + app); 2287 mConnectedAgent = null; 2288 } 2289 if (DEBUG) Slog.i(TAG, "got agent " + mConnectedAgent); 2290 agent = mConnectedAgent; 2291 } 2292 } catch (RemoteException e) { 2293 // can't happen - ActivityManager is local 2294 } 2295 } 2296 if (agent == null) { 2297 try { 2298 mActivityManager.clearPendingBackup(); 2299 } catch (RemoteException e) { 2300 // can't happen - ActivityManager is local 2301 } 2302 } 2303 return agent; 2304 } 2305 2306 // clear an application's data, blocking until the operation completes or times out 2307 void clearApplicationDataSynchronous(String packageName) { 2308 // Don't wipe packages marked allowClearUserData=false 2309 try { 2310 PackageInfo info = mPackageManager.getPackageInfo(packageName, 0); 2311 if ((info.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA) == 0) { 2312 if (MORE_DEBUG) Slog.i(TAG, "allowClearUserData=false so not wiping " 2313 + packageName); 2314 return; 2315 } 2316 } catch (NameNotFoundException e) { 2317 Slog.w(TAG, "Tried to clear data for " + packageName + " but not found"); 2318 return; 2319 } 2320 2321 ClearDataObserver observer = new ClearDataObserver(); 2322 2323 synchronized(mClearDataLock) { 2324 mClearingData = true; 2325 try { 2326 mActivityManager.clearApplicationUserData(packageName, observer, 0); 2327 } catch (RemoteException e) { 2328 // can't happen because the activity manager is in this process 2329 } 2330 2331 // only wait 10 seconds for the clear data to happen 2332 long timeoutMark = System.currentTimeMillis() + TIMEOUT_INTERVAL; 2333 while (mClearingData && (System.currentTimeMillis() < timeoutMark)) { 2334 try { 2335 mClearDataLock.wait(5000); 2336 } catch (InterruptedException e) { 2337 // won't happen, but still. 2338 mClearingData = false; 2339 } 2340 } 2341 } 2342 } 2343 2344 class ClearDataObserver extends IPackageDataObserver.Stub { 2345 public void onRemoveCompleted(String packageName, boolean succeeded) { 2346 synchronized(mClearDataLock) { 2347 mClearingData = false; 2348 mClearDataLock.notifyAll(); 2349 } 2350 } 2351 } 2352 2353 // Get the restore-set token for the best-available restore set for this package: 2354 // the active set if possible, else the ancestral one. Returns zero if none available. 2355 public long getAvailableRestoreToken(String packageName) { 2356 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, 2357 "getAvailableRestoreToken"); 2358 2359 long token = mAncestralToken; 2360 synchronized (mQueueLock) { 2361 if (mEverStoredApps.contains(packageName)) { 2362 if (MORE_DEBUG) { 2363 Slog.i(TAG, "App in ever-stored, so using current token"); 2364 } 2365 token = mCurrentToken; 2366 } 2367 } 2368 if (MORE_DEBUG) Slog.i(TAG, "getAvailableRestoreToken() == " + token); 2369 return token; 2370 } 2371 2372 public int requestBackup(String[] packages, IBackupObserver observer, int flags) { 2373 return requestBackup(packages, observer, null, flags); 2374 } 2375 2376 public int requestBackup(String[] packages, IBackupObserver observer, 2377 IBackupManagerMonitor monitor, int flags) { 2378 mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "requestBackup"); 2379 2380 if (packages == null || packages.length < 1) { 2381 Slog.e(TAG, "No packages named for backup request"); 2382 sendBackupFinished(observer, BackupManager.ERROR_TRANSPORT_ABORTED); 2383 monitor = monitorEvent(monitor, BackupManagerMonitor.LOG_EVENT_ID_NO_PACKAGES, 2384 null, BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT, null); 2385 throw new IllegalArgumentException("No packages are provided for backup"); 2386 } 2387 2388 IBackupTransport transport = mTransportManager.getCurrentTransportBinder(); 2389 if (transport == null) { 2390 sendBackupFinished(observer, BackupManager.ERROR_TRANSPORT_ABORTED); 2391 monitor = monitorEvent(monitor, BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_IS_NULL, 2392 null, BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT, null); 2393 return BackupManager.ERROR_TRANSPORT_ABORTED; 2394 } 2395 2396 ArrayList<String> fullBackupList = new ArrayList<>(); 2397 ArrayList<String> kvBackupList = new ArrayList<>(); 2398 for (String packageName : packages) { 2399 if (PACKAGE_MANAGER_SENTINEL.equals(packageName)) { 2400 kvBackupList.add(packageName); 2401 continue; 2402 } 2403 try { 2404 PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, 2405 PackageManager.GET_SIGNATURES); 2406 if (!appIsEligibleForBackup(packageInfo.applicationInfo)) { 2407 sendBackupOnPackageResult(observer, packageName, 2408 BackupManager.ERROR_BACKUP_NOT_ALLOWED); 2409 continue; 2410 } 2411 if (appGetsFullBackup(packageInfo)) { 2412 fullBackupList.add(packageInfo.packageName); 2413 } else { 2414 kvBackupList.add(packageInfo.packageName); 2415 } 2416 } catch (NameNotFoundException e) { 2417 sendBackupOnPackageResult(observer, packageName, 2418 BackupManager.ERROR_PACKAGE_NOT_FOUND); 2419 } 2420 } 2421 EventLog.writeEvent(EventLogTags.BACKUP_REQUESTED, packages.length, kvBackupList.size(), 2422 fullBackupList.size()); 2423 if (MORE_DEBUG) { 2424 Slog.i(TAG, "Backup requested for " + packages.length + " packages, of them: " + 2425 fullBackupList.size() + " full backups, " + kvBackupList.size() + " k/v backups"); 2426 } 2427 2428 String dirName; 2429 try { 2430 dirName = transport.transportDirName(); 2431 } catch (Exception e) { 2432 Slog.e(TAG, "Transport unavailable while attempting backup: " + e.getMessage()); 2433 sendBackupFinished(observer, BackupManager.ERROR_TRANSPORT_ABORTED); 2434 return BackupManager.ERROR_TRANSPORT_ABORTED; 2435 } 2436 2437 boolean nonIncrementalBackup = (flags & BackupManager.FLAG_NON_INCREMENTAL_BACKUP) != 0; 2438 2439 Message msg = mBackupHandler.obtainMessage(MSG_REQUEST_BACKUP); 2440 msg.obj = new BackupParams(transport, dirName, kvBackupList, fullBackupList, observer, 2441 monitor, true, nonIncrementalBackup); 2442 mBackupHandler.sendMessage(msg); 2443 return BackupManager.SUCCESS; 2444 } 2445 2446 // Cancel all running backups. 2447 public void cancelBackups(){ 2448 mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "cancelBackups"); 2449 if (MORE_DEBUG) { 2450 Slog.i(TAG, "cancelBackups() called."); 2451 } 2452 final long oldToken = Binder.clearCallingIdentity(); 2453 try { 2454 List<Integer> operationsToCancel = new ArrayList<>(); 2455 synchronized (mCurrentOpLock) { 2456 for (int i = 0; i < mCurrentOperations.size(); i++) { 2457 Operation op = mCurrentOperations.valueAt(i); 2458 int token = mCurrentOperations.keyAt(i); 2459 if (op.type == OP_TYPE_BACKUP) { 2460 operationsToCancel.add(token); 2461 } 2462 } 2463 2464 for (Integer token : operationsToCancel) { 2465 handleCancel(token, true /* cancelAll */); 2466 } 2467 } 2468 2469 // We don't want the backup jobs to kick in any time soon. 2470 // Reschedules them to run in the distant future. 2471 KeyValueBackupJob.schedule(mContext, BUSY_BACKOFF_MIN_MILLIS); 2472 FullBackupJob.schedule(mContext, 2 * BUSY_BACKOFF_MIN_MILLIS); 2473 } finally { 2474 Binder.restoreCallingIdentity(oldToken); 2475 } 2476 } 2477 2478 // ----- 2479 // Interface and methods used by the asynchronous-with-timeout backup/restore operations 2480 2481 interface BackupRestoreTask { 2482 // Execute one tick of whatever state machine the task implements 2483 void execute(); 2484 2485 // An operation that wanted a callback has completed 2486 void operationComplete(long result); 2487 2488 // An operation that wanted a callback has timed out 2489 void handleCancel(boolean cancelAll); 2490 } 2491 2492 void prepareOperationTimeout(int token, long interval, BackupRestoreTask callback, 2493 int operationType) { 2494 if (operationType != OP_TYPE_BACKUP_WAIT && operationType != OP_TYPE_RESTORE_WAIT) { 2495 Slog.wtf(TAG, "prepareOperationTimeout() doesn't support operation " + 2496 Integer.toHexString(token) + " of type " + operationType); 2497 return; 2498 } 2499 if (MORE_DEBUG) Slog.v(TAG, "starting timeout: token=" + Integer.toHexString(token) 2500 + " interval=" + interval + " callback=" + callback); 2501 2502 synchronized (mCurrentOpLock) { 2503 mCurrentOperations.put(token, new Operation(OP_PENDING, callback, operationType)); 2504 Message msg = mBackupHandler.obtainMessage(getMessageIdForOperationType(operationType), 2505 token, 0, callback); 2506 mBackupHandler.sendMessageDelayed(msg, interval); 2507 } 2508 } 2509 2510 private int getMessageIdForOperationType(int operationType) { 2511 switch (operationType) { 2512 case OP_TYPE_BACKUP_WAIT: 2513 return MSG_BACKUP_OPERATION_TIMEOUT; 2514 case OP_TYPE_RESTORE_WAIT: 2515 return MSG_RESTORE_OPERATION_TIMEOUT; 2516 default: 2517 Slog.wtf(TAG, "getMessageIdForOperationType called on invalid operation type: " + 2518 operationType); 2519 return -1; 2520 } 2521 } 2522 2523 private void removeOperation(int token) { 2524 if (MORE_DEBUG) { 2525 Slog.d(TAG, "Removing operation token=" + Integer.toHexString(token)); 2526 } 2527 synchronized (mCurrentOpLock) { 2528 if (mCurrentOperations.get(token) == null) { 2529 Slog.w(TAG, "Duplicate remove for operation. token=" + 2530 Integer.toHexString(token)); 2531 } 2532 mCurrentOperations.remove(token); 2533 } 2534 } 2535 2536 // synchronous waiter case 2537 boolean waitUntilOperationComplete(int token) { 2538 if (MORE_DEBUG) Slog.i(TAG, "Blocking until operation complete for " 2539 + Integer.toHexString(token)); 2540 int finalState = OP_PENDING; 2541 Operation op = null; 2542 synchronized (mCurrentOpLock) { 2543 while (true) { 2544 op = mCurrentOperations.get(token); 2545 if (op == null) { 2546 // mysterious disappearance: treat as success with no callback 2547 break; 2548 } else { 2549 if (op.state == OP_PENDING) { 2550 try { 2551 mCurrentOpLock.wait(); 2552 } catch (InterruptedException e) { 2553 } 2554 // When the wait is notified we loop around and recheck the current state 2555 } else { 2556 if (MORE_DEBUG) { 2557 Slog.d(TAG, "Unblocked waiting for operation token=" + 2558 Integer.toHexString(token)); 2559 } 2560 // No longer pending; we're done 2561 finalState = op.state; 2562 break; 2563 } 2564 } 2565 } 2566 } 2567 2568 removeOperation(token); 2569 if (op != null) { 2570 mBackupHandler.removeMessages(getMessageIdForOperationType(op.type)); 2571 } 2572 if (MORE_DEBUG) Slog.v(TAG, "operation " + Integer.toHexString(token) 2573 + " complete: finalState=" + finalState); 2574 return finalState == OP_ACKNOWLEDGED; 2575 } 2576 2577 void handleCancel(int token, boolean cancelAll) { 2578 // Notify any synchronous waiters 2579 Operation op = null; 2580 synchronized (mCurrentOpLock) { 2581 op = mCurrentOperations.get(token); 2582 if (MORE_DEBUG) { 2583 if (op == null) Slog.w(TAG, "Cancel of token " + Integer.toHexString(token) 2584 + " but no op found"); 2585 } 2586 int state = (op != null) ? op.state : OP_TIMEOUT; 2587 if (state == OP_ACKNOWLEDGED) { 2588 // The operation finished cleanly, so we have nothing more to do. 2589 if (DEBUG) { 2590 Slog.w(TAG, "Operation already got an ack." + 2591 "Should have been removed from mCurrentOperations."); 2592 } 2593 op = null; 2594 mCurrentOperations.delete(token); 2595 } else if (state == OP_PENDING) { 2596 if (DEBUG) Slog.v(TAG, "Cancel: token=" + Integer.toHexString(token)); 2597 op.state = OP_TIMEOUT; 2598 // Can't delete op from mCurrentOperations here. waitUntilOperationComplete may be 2599 // called after we receive cancel here. We need this op's state there. 2600 2601 // Remove all pending timeout messages for this operation type. 2602 mBackupHandler.removeMessages(getMessageIdForOperationType(op.type)); 2603 } 2604 mCurrentOpLock.notifyAll(); 2605 } 2606 2607 // If there's a TimeoutHandler for this event, call it 2608 if (op != null && op.callback != null) { 2609 if (MORE_DEBUG) { 2610 Slog.v(TAG, " Invoking cancel on " + op.callback); 2611 } 2612 op.callback.handleCancel(cancelAll); 2613 } 2614 } 2615 2616 // ----- Back up a set of applications via a worker thread ----- 2617 2618 enum BackupState { 2619 INITIAL, 2620 RUNNING_QUEUE, 2621 FINAL 2622 } 2623 2624 /** 2625 * This class handles the process of backing up a given list of key/value backup packages. 2626 * Also takes in a list of pending dolly backups and kicks them off when key/value backups 2627 * are done. 2628 * 2629 * Flow: 2630 * If required, backup @pm@. 2631 * For each pending key/value backup package: 2632 * - Bind to agent. 2633 * - Call agent.doBackup() 2634 * - Wait either for cancel/timeout or operationComplete() callback from the agent. 2635 * Start task to perform dolly backups. 2636 * 2637 * There are three entry points into this class: 2638 * - execute() [Called from the handler thread] 2639 * - operationComplete(long result) [Called from the handler thread] 2640 * - handleCancel(boolean cancelAll) [Can be called from any thread] 2641 * These methods synchronize on mCancelLock. 2642 * 2643 * Interaction with mCurrentOperations: 2644 * - An entry for this task is put into mCurrentOperations for the entire lifetime of the 2645 * task. This is useful to cancel the task if required. 2646 * - An ephemeral entry is put into mCurrentOperations each time we are waiting on for 2647 * response from a backup agent. This is used to plumb timeouts and completion callbacks. 2648 */ 2649 class PerformBackupTask implements BackupRestoreTask { 2650 private static final String TAG = "PerformBackupTask"; 2651 2652 private final Object mCancelLock = new Object(); 2653 2654 IBackupTransport mTransport; 2655 ArrayList<BackupRequest> mQueue; 2656 ArrayList<BackupRequest> mOriginalQueue; 2657 File mStateDir; 2658 File mJournal; 2659 BackupState mCurrentState; 2660 ArrayList<String> mPendingFullBackups; 2661 IBackupObserver mObserver; 2662 IBackupManagerMonitor mMonitor; 2663 2664 private final PerformFullTransportBackupTask mFullBackupTask; 2665 private final int mCurrentOpToken; 2666 private volatile int mEphemeralOpToken; 2667 2668 // carried information about the current in-flight operation 2669 IBackupAgent mAgentBinder; 2670 PackageInfo mCurrentPackage; 2671 File mSavedStateName; 2672 File mBackupDataName; 2673 File mNewStateName; 2674 ParcelFileDescriptor mSavedState; 2675 ParcelFileDescriptor mBackupData; 2676 ParcelFileDescriptor mNewState; 2677 int mStatus; 2678 boolean mFinished; 2679 final boolean mUserInitiated; 2680 final boolean mNonIncremental; 2681 2682 private volatile boolean mCancelAll; 2683 2684 public PerformBackupTask(IBackupTransport transport, String dirName, 2685 ArrayList<BackupRequest> queue, File journal, IBackupObserver observer, 2686 IBackupManagerMonitor monitor, ArrayList<String> pendingFullBackups, 2687 boolean userInitiated, boolean nonIncremental) { 2688 mTransport = transport; 2689 mOriginalQueue = queue; 2690 mQueue = new ArrayList<>(); 2691 mJournal = journal; 2692 mObserver = observer; 2693 mMonitor = monitor; 2694 mPendingFullBackups = pendingFullBackups; 2695 mUserInitiated = userInitiated; 2696 mNonIncremental = nonIncremental; 2697 2698 mStateDir = new File(mBaseStateDir, dirName); 2699 mCurrentOpToken = generateToken(); 2700 2701 mFinished = false; 2702 2703 synchronized (mCurrentOpLock) { 2704 if (isBackupOperationInProgress()) { 2705 if (DEBUG) { 2706 Slog.d(TAG, "Skipping backup since one is already in progress."); 2707 } 2708 mCancelAll = true; 2709 mFullBackupTask = null; 2710 mCurrentState = BackupState.FINAL; 2711 addBackupTrace("Skipped. Backup already in progress."); 2712 } else { 2713 mCurrentState = BackupState.INITIAL; 2714 CountDownLatch latch = new CountDownLatch(1); 2715 String[] fullBackups = 2716 mPendingFullBackups.toArray(new String[mPendingFullBackups.size()]); 2717 mFullBackupTask = 2718 new PerformFullTransportBackupTask(/*fullBackupRestoreObserver*/ null, 2719 fullBackups, /*updateSchedule*/ false, /*runningJob*/ null, 2720 latch, 2721 mObserver, mMonitor, mUserInitiated); 2722 2723 registerTask(); 2724 addBackupTrace("STATE => INITIAL"); 2725 } 2726 } 2727 } 2728 2729 /** 2730 * Put this task in the repository of running tasks. 2731 */ 2732 private void registerTask() { 2733 synchronized (mCurrentOpLock) { 2734 mCurrentOperations.put(mCurrentOpToken, new Operation(OP_PENDING, this, 2735 OP_TYPE_BACKUP)); 2736 } 2737 } 2738 2739 /** 2740 * Remove this task from repository of running tasks. 2741 */ 2742 private void unregisterTask() { 2743 removeOperation(mCurrentOpToken); 2744 } 2745 2746 // Main entry point: perform one chunk of work, updating the state as appropriate 2747 // and reposting the next chunk to the primary backup handler thread. 2748 @Override 2749 @GuardedBy("mCancelLock") 2750 public void execute() { 2751 synchronized (mCancelLock) { 2752 switch (mCurrentState) { 2753 case INITIAL: 2754 beginBackup(); 2755 break; 2756 2757 case RUNNING_QUEUE: 2758 invokeNextAgent(); 2759 break; 2760 2761 case FINAL: 2762 if (!mFinished) finalizeBackup(); 2763 else { 2764 Slog.e(TAG, "Duplicate finish"); 2765 } 2766 mFinished = true; 2767 break; 2768 } 2769 } 2770 } 2771 2772 // We're starting a backup pass. Initialize the transport and send 2773 // the PM metadata blob if we haven't already. 2774 void beginBackup() { 2775 if (DEBUG_BACKUP_TRACE) { 2776 clearBackupTrace(); 2777 StringBuilder b = new StringBuilder(256); 2778 b.append("beginBackup: ["); 2779 for (BackupRequest req : mOriginalQueue) { 2780 b.append(' '); 2781 b.append(req.packageName); 2782 } 2783 b.append(" ]"); 2784 addBackupTrace(b.toString()); 2785 } 2786 2787 mAgentBinder = null; 2788 mStatus = BackupTransport.TRANSPORT_OK; 2789 2790 // Sanity check: if the queue is empty we have no work to do. 2791 if (mOriginalQueue.isEmpty() && mPendingFullBackups.isEmpty()) { 2792 Slog.w(TAG, "Backup begun with an empty queue - nothing to do."); 2793 addBackupTrace("queue empty at begin"); 2794 sendBackupFinished(mObserver, BackupManager.SUCCESS); 2795 executeNextState(BackupState.FINAL); 2796 return; 2797 } 2798 2799 // We need to retain the original queue contents in case of transport 2800 // failure, but we want a working copy that we can manipulate along 2801 // the way. 2802 mQueue = (ArrayList<BackupRequest>) mOriginalQueue.clone(); 2803 2804 // When the transport is forcing non-incremental key/value payloads, we send the 2805 // metadata only if it explicitly asks for it. 2806 boolean skipPm = mNonIncremental; 2807 2808 // The app metadata pseudopackage might also be represented in the 2809 // backup queue if apps have been added/removed since the last time 2810 // we performed a backup. Drop it from the working queue now that 2811 // we're committed to evaluating it for backup regardless. 2812 for (int i = 0; i < mQueue.size(); i++) { 2813 if (PACKAGE_MANAGER_SENTINEL.equals(mQueue.get(i).packageName)) { 2814 if (MORE_DEBUG) { 2815 Slog.i(TAG, "Metadata in queue; eliding"); 2816 } 2817 mQueue.remove(i); 2818 skipPm = false; 2819 break; 2820 } 2821 } 2822 2823 if (DEBUG) Slog.v(TAG, "Beginning backup of " + mQueue.size() + " targets"); 2824 2825 File pmState = new File(mStateDir, PACKAGE_MANAGER_SENTINEL); 2826 try { 2827 final String transportName = mTransport.transportDirName(); 2828 EventLog.writeEvent(EventLogTags.BACKUP_START, transportName); 2829 2830 // If we haven't stored package manager metadata yet, we must init the transport. 2831 if (mStatus == BackupTransport.TRANSPORT_OK && pmState.length() <= 0) { 2832 Slog.i(TAG, "Initializing (wiping) backup state and transport storage"); 2833 addBackupTrace("initializing transport " + transportName); 2834 resetBackupState(mStateDir); // Just to make sure. 2835 mStatus = mTransport.initializeDevice(); 2836 2837 addBackupTrace("transport.initializeDevice() == " + mStatus); 2838 if (mStatus == BackupTransport.TRANSPORT_OK) { 2839 EventLog.writeEvent(EventLogTags.BACKUP_INITIALIZE); 2840 } else { 2841 EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, "(initialize)"); 2842 Slog.e(TAG, "Transport error in initializeDevice()"); 2843 } 2844 } 2845 2846 if (skipPm) { 2847 Slog.d(TAG, "Skipping backup of package metadata."); 2848 executeNextState(BackupState.RUNNING_QUEUE); 2849 } else { 2850 // The package manager doesn't have a proper <application> etc, but since 2851 // it's running here in the system process we can just set up its agent 2852 // directly and use a synthetic BackupRequest. We always run this pass 2853 // because it's cheap and this way we guarantee that we don't get out of 2854 // step even if we're selecting among various transports at run time. 2855 if (mStatus == BackupTransport.TRANSPORT_OK) { 2856 PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent( 2857 mPackageManager); 2858 mStatus = invokeAgentForBackup(PACKAGE_MANAGER_SENTINEL, 2859 IBackupAgent.Stub.asInterface(pmAgent.onBind()), mTransport); 2860 addBackupTrace("PMBA invoke: " + mStatus); 2861 2862 // Because the PMBA is a local instance, it has already executed its 2863 // backup callback and returned. Blow away the lingering (spurious) 2864 // pending timeout message for it. 2865 mBackupHandler.removeMessages(MSG_BACKUP_OPERATION_TIMEOUT); 2866 } 2867 } 2868 2869 if (mStatus == BackupTransport.TRANSPORT_NOT_INITIALIZED) { 2870 // The backend reports that our dataset has been wiped. Note this in 2871 // the event log; the no-success code below will reset the backup 2872 // state as well. 2873 EventLog.writeEvent(EventLogTags.BACKUP_RESET, mTransport.transportDirName()); 2874 } 2875 } catch (Exception e) { 2876 Slog.e(TAG, "Error in backup thread", e); 2877 addBackupTrace("Exception in backup thread: " + e); 2878 mStatus = BackupTransport.TRANSPORT_ERROR; 2879 } finally { 2880 // If we've succeeded so far, invokeAgentForBackup() will have run the PM 2881 // metadata and its completion/timeout callback will continue the state 2882 // machine chain. If it failed that won't happen; we handle that now. 2883 addBackupTrace("exiting prelim: " + mStatus); 2884 if (mStatus != BackupTransport.TRANSPORT_OK) { 2885 // if things went wrong at this point, we need to 2886 // restage everything and try again later. 2887 resetBackupState(mStateDir); // Just to make sure. 2888 // In case of any other error, it's backup transport error. 2889 sendBackupFinished(mObserver, BackupManager.ERROR_TRANSPORT_ABORTED); 2890 executeNextState(BackupState.FINAL); 2891 } 2892 } 2893 } 2894 2895 // Transport has been initialized and the PM metadata submitted successfully 2896 // if that was warranted. Now we process the single next thing in the queue. 2897 void invokeNextAgent() { 2898 mStatus = BackupTransport.TRANSPORT_OK; 2899 addBackupTrace("invoke q=" + mQueue.size()); 2900 2901 // Sanity check that we have work to do. If not, skip to the end where 2902 // we reestablish the wakelock invariants etc. 2903 if (mQueue.isEmpty()) { 2904 if (MORE_DEBUG) Slog.i(TAG, "queue now empty"); 2905 executeNextState(BackupState.FINAL); 2906 return; 2907 } 2908 2909 // pop the entry we're going to process on this step 2910 BackupRequest request = mQueue.get(0); 2911 mQueue.remove(0); 2912 2913 Slog.d(TAG, "starting key/value backup of " + request); 2914 addBackupTrace("launch agent for " + request.packageName); 2915 2916 // Verify that the requested app exists; it might be something that 2917 // requested a backup but was then uninstalled. The request was 2918 // journalled and rather than tamper with the journal it's safer 2919 // to sanity-check here. This also gives us the classname of the 2920 // package's backup agent. 2921 try { 2922 mCurrentPackage = mPackageManager.getPackageInfo(request.packageName, 2923 PackageManager.GET_SIGNATURES); 2924 if (!appIsEligibleForBackup(mCurrentPackage.applicationInfo)) { 2925 // The manifest has changed but we had a stale backup request pending. 2926 // This won't happen again because the app won't be requesting further 2927 // backups. 2928 Slog.i(TAG, "Package " + request.packageName 2929 + " no longer supports backup; skipping"); 2930 addBackupTrace("skipping - not eligible, completion is noop"); 2931 // Shouldn't happen in case of requested backup, as pre-check was done in 2932 // #requestBackup(), except to app update done concurrently 2933 sendBackupOnPackageResult(mObserver, mCurrentPackage.packageName, 2934 BackupManager.ERROR_BACKUP_NOT_ALLOWED); 2935 executeNextState(BackupState.RUNNING_QUEUE); 2936 return; 2937 } 2938 2939 if (appGetsFullBackup(mCurrentPackage)) { 2940 // It's possible that this app *formerly* was enqueued for key/value backup, 2941 // but has since been updated and now only supports the full-data path. 2942 // Don't proceed with a key/value backup for it in this case. 2943 Slog.i(TAG, "Package " + request.packageName 2944 + " requests full-data rather than key/value; skipping"); 2945 addBackupTrace("skipping - fullBackupOnly, completion is noop"); 2946 // Shouldn't happen in case of requested backup, as pre-check was done in 2947 // #requestBackup() 2948 sendBackupOnPackageResult(mObserver, mCurrentPackage.packageName, 2949 BackupManager.ERROR_BACKUP_NOT_ALLOWED); 2950 executeNextState(BackupState.RUNNING_QUEUE); 2951 return; 2952 } 2953 2954 if (appIsStopped(mCurrentPackage.applicationInfo)) { 2955 // The app has been force-stopped or cleared or just installed, 2956 // and not yet launched out of that state, so just as it won't 2957 // receive broadcasts, we won't run it for backup. 2958 addBackupTrace("skipping - stopped"); 2959 sendBackupOnPackageResult(mObserver, mCurrentPackage.packageName, 2960 BackupManager.ERROR_BACKUP_NOT_ALLOWED); 2961 executeNextState(BackupState.RUNNING_QUEUE); 2962 return; 2963 } 2964 2965 IBackupAgent agent = null; 2966 try { 2967 mWakelock.setWorkSource(new WorkSource(mCurrentPackage.applicationInfo.uid)); 2968 agent = bindToAgentSynchronous(mCurrentPackage.applicationInfo, 2969 ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL); 2970 addBackupTrace("agent bound; a? = " + (agent != null)); 2971 if (agent != null) { 2972 mAgentBinder = agent; 2973 mStatus = invokeAgentForBackup(request.packageName, agent, mTransport); 2974 // at this point we'll either get a completion callback from the 2975 // agent, or a timeout message on the main handler. either way, we're 2976 // done here as long as we're successful so far. 2977 } else { 2978 // Timeout waiting for the agent 2979 mStatus = BackupTransport.AGENT_ERROR; 2980 } 2981 } catch (SecurityException ex) { 2982 // Try for the next one. 2983 Slog.d(TAG, "error in bind/backup", ex); 2984 mStatus = BackupTransport.AGENT_ERROR; 2985 addBackupTrace("agent SE"); 2986 } 2987 } catch (NameNotFoundException e) { 2988 Slog.d(TAG, "Package does not exist; skipping"); 2989 addBackupTrace("no such package"); 2990 mStatus = BackupTransport.AGENT_UNKNOWN; 2991 } finally { 2992 mWakelock.setWorkSource(null); 2993 2994 // If there was an agent error, no timeout/completion handling will occur. 2995 // That means we need to direct to the next state ourselves. 2996 if (mStatus != BackupTransport.TRANSPORT_OK) { 2997 BackupState nextState = BackupState.RUNNING_QUEUE; 2998 mAgentBinder = null; 2999 3000 // An agent-level failure means we reenqueue this one agent for 3001 // a later retry, but otherwise proceed normally. 3002 if (mStatus == BackupTransport.AGENT_ERROR) { 3003 if (MORE_DEBUG) Slog.i(TAG, "Agent failure for " + request.packageName 3004 + " - restaging"); 3005 dataChangedImpl(request.packageName); 3006 mStatus = BackupTransport.TRANSPORT_OK; 3007 if (mQueue.isEmpty()) nextState = BackupState.FINAL; 3008 sendBackupOnPackageResult(mObserver, mCurrentPackage.packageName, 3009 BackupManager.ERROR_AGENT_FAILURE); 3010 } else if (mStatus == BackupTransport.AGENT_UNKNOWN) { 3011 // Failed lookup of the app, so we couldn't bring up an agent, but 3012 // we're otherwise fine. Just drop it and go on to the next as usual. 3013 mStatus = BackupTransport.TRANSPORT_OK; 3014 sendBackupOnPackageResult(mObserver, mCurrentPackage.packageName, 3015 BackupManager.ERROR_PACKAGE_NOT_FOUND); 3016 } else { 3017 // Transport-level failure means we reenqueue everything 3018 revertAndEndBackup(); 3019 nextState = BackupState.FINAL; 3020 } 3021 3022 executeNextState(nextState); 3023 } else { 3024 // success case 3025 addBackupTrace("expecting completion/timeout callback"); 3026 } 3027 } 3028 } 3029 3030 void finalizeBackup() { 3031 addBackupTrace("finishing"); 3032 3033 // Mark packages that we didn't backup (because backup was cancelled, etc.) as needing 3034 // backup. 3035 for (BackupRequest req : mQueue) { 3036 dataChangedImpl(req.packageName); 3037 } 3038 3039 // Either backup was successful, in which case we of course do not need 3040 // this pass's journal any more; or it failed, in which case we just 3041 // re-enqueued all of these packages in the current active journal. 3042 // Either way, we no longer need this pass's journal. 3043 if (mJournal != null && !mJournal.delete()) { 3044 Slog.e(TAG, "Unable to remove backup journal file " + mJournal); 3045 } 3046 3047 // If everything actually went through and this is the first time we've 3048 // done a backup, we can now record what the current backup dataset token 3049 // is. 3050 if ((mCurrentToken == 0) && (mStatus == BackupTransport.TRANSPORT_OK)) { 3051 addBackupTrace("success; recording token"); 3052 try { 3053 mCurrentToken = mTransport.getCurrentRestoreSet(); 3054 writeRestoreTokens(); 3055 } catch (Exception e) { 3056 // nothing for it at this point, unfortunately, but this will be 3057 // recorded the next time we fully succeed. 3058 Slog.e(TAG, "Transport threw reporting restore set: " + e.getMessage()); 3059 addBackupTrace("transport threw returning token"); 3060 } 3061 } 3062 3063 // Set up the next backup pass - at this point we can set mBackupRunning 3064 // to false to allow another pass to fire, because we're done with the 3065 // state machine sequence and the wakelock is refcounted. 3066 synchronized (mQueueLock) { 3067 mBackupRunning = false; 3068 if (mStatus == BackupTransport.TRANSPORT_NOT_INITIALIZED) { 3069 // Make sure we back up everything and perform the one-time init 3070 if (MORE_DEBUG) Slog.d(TAG, "Server requires init; rerunning"); 3071 addBackupTrace("init required; rerunning"); 3072 try { 3073 final String name = mTransportManager.getTransportName(mTransport); 3074 if (name != null) { 3075 mPendingInits.add(name); 3076 } else { 3077 if (DEBUG) { 3078 Slog.w(TAG, "Couldn't find name of transport " + mTransport 3079 + " for init"); 3080 } 3081 } 3082 } catch (Exception e) { 3083 Slog.w(TAG, "Failed to query transport name for init: " + e.getMessage()); 3084 // swallow it and proceed; we don't rely on this 3085 } 3086 clearMetadata(); 3087 backupNow(); 3088 } 3089 } 3090 3091 clearBackupTrace(); 3092 3093 unregisterTask(); 3094 3095 if (!mCancelAll && mStatus == BackupTransport.TRANSPORT_OK && 3096 mPendingFullBackups != null && !mPendingFullBackups.isEmpty()) { 3097 Slog.d(TAG, "Starting full backups for: " + mPendingFullBackups); 3098 CountDownLatch latch = new CountDownLatch(1); 3099 String[] fullBackups = 3100 mPendingFullBackups.toArray(new String[mPendingFullBackups.size()]); 3101 PerformFullTransportBackupTask task = 3102 new PerformFullTransportBackupTask(/*fullBackupRestoreObserver*/ null, 3103 fullBackups, /*updateSchedule*/ false, /*runningJob*/ null, latch, 3104 mObserver, mMonitor, mUserInitiated); 3105 // Acquiring wakelock for PerformFullTransportBackupTask before its start. 3106 mWakelock.acquire(); 3107 (new Thread(mFullBackupTask, "full-transport-requested")).start(); 3108 } else if (mCancelAll) { 3109 if (mFullBackupTask != null) { 3110 mFullBackupTask.unregisterTask(); 3111 } 3112 sendBackupFinished(mObserver, BackupManager.ERROR_BACKUP_CANCELLED); 3113 } else { 3114 mFullBackupTask.unregisterTask(); 3115 switch (mStatus) { 3116 case BackupTransport.TRANSPORT_OK: 3117 sendBackupFinished(mObserver, BackupManager.SUCCESS); 3118 break; 3119 case BackupTransport.TRANSPORT_NOT_INITIALIZED: 3120 sendBackupFinished(mObserver, BackupManager.ERROR_TRANSPORT_ABORTED); 3121 break; 3122 case BackupTransport.TRANSPORT_ERROR: 3123 default: 3124 sendBackupFinished(mObserver, BackupManager.ERROR_TRANSPORT_ABORTED); 3125 break; 3126 } 3127 } 3128 Slog.i(BackupManagerService.TAG, "K/V backup pass finished."); 3129 // Only once we're entirely finished do we release the wakelock for k/v backup. 3130 mWakelock.release(); 3131 } 3132 3133 // Remove the PM metadata state. This will generate an init on the next pass. 3134 void clearMetadata() { 3135 final File pmState = new File(mStateDir, PACKAGE_MANAGER_SENTINEL); 3136 if (pmState.exists()) pmState.delete(); 3137 } 3138 3139 // Invoke an agent's doBackup() and start a timeout message spinning on the main 3140 // handler in case it doesn't get back to us. 3141 int invokeAgentForBackup(String packageName, IBackupAgent agent, 3142 IBackupTransport transport) { 3143 if (DEBUG) Slog.d(TAG, "invokeAgentForBackup on " + packageName); 3144 addBackupTrace("invoking " + packageName); 3145 3146 File blankStateName = new File(mStateDir, "blank_state"); 3147 mSavedStateName = new File(mStateDir, packageName); 3148 mBackupDataName = new File(mDataDir, packageName + ".data"); 3149 mNewStateName = new File(mStateDir, packageName + ".new"); 3150 if (MORE_DEBUG) Slog.d(TAG, "data file: " + mBackupDataName); 3151 3152 mSavedState = null; 3153 mBackupData = null; 3154 mNewState = null; 3155 3156 boolean callingAgent = false; 3157 mEphemeralOpToken = generateToken(); 3158 try { 3159 // Look up the package info & signatures. This is first so that if it 3160 // throws an exception, there's no file setup yet that would need to 3161 // be unraveled. 3162 if (packageName.equals(PACKAGE_MANAGER_SENTINEL)) { 3163 // The metadata 'package' is synthetic; construct one and make 3164 // sure our global state is pointed at it 3165 mCurrentPackage = new PackageInfo(); 3166 mCurrentPackage.packageName = packageName; 3167 } 3168 3169 // In a full backup, we pass a null ParcelFileDescriptor as 3170 // the saved-state "file". For key/value backups we pass the old state if 3171 // an incremental backup is required, and a blank state otherwise. 3172 mSavedState = ParcelFileDescriptor.open( 3173 mNonIncremental ? blankStateName : mSavedStateName, 3174 ParcelFileDescriptor.MODE_READ_ONLY | 3175 ParcelFileDescriptor.MODE_CREATE); // Make an empty file if necessary 3176 3177 mBackupData = ParcelFileDescriptor.open(mBackupDataName, 3178 ParcelFileDescriptor.MODE_READ_WRITE | 3179 ParcelFileDescriptor.MODE_CREATE | 3180 ParcelFileDescriptor.MODE_TRUNCATE); 3181 3182 if (!SELinux.restorecon(mBackupDataName)) { 3183 Slog.e(TAG, "SELinux restorecon failed on " + mBackupDataName); 3184 } 3185 3186 mNewState = ParcelFileDescriptor.open(mNewStateName, 3187 ParcelFileDescriptor.MODE_READ_WRITE | 3188 ParcelFileDescriptor.MODE_CREATE | 3189 ParcelFileDescriptor.MODE_TRUNCATE); 3190 3191 final long quota = mTransport.getBackupQuota(packageName, false /* isFullBackup */); 3192 callingAgent = true; 3193 3194 // Initiate the target's backup pass 3195 addBackupTrace("setting timeout"); 3196 prepareOperationTimeout(mEphemeralOpToken, TIMEOUT_BACKUP_INTERVAL, this, 3197 OP_TYPE_BACKUP_WAIT); 3198 addBackupTrace("calling agent doBackup()"); 3199 3200 agent.doBackup(mSavedState, mBackupData, mNewState, quota, mEphemeralOpToken, 3201 mBackupManagerBinder); 3202 } catch (Exception e) { 3203 Slog.e(TAG, "Error invoking for backup on " + packageName + ". " + e); 3204 addBackupTrace("exception: " + e); 3205 EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName, 3206 e.toString()); 3207 errorCleanup(); 3208 return callingAgent ? BackupTransport.AGENT_ERROR 3209 : BackupTransport.TRANSPORT_ERROR; 3210 } finally { 3211 if (mNonIncremental) { 3212 blankStateName.delete(); 3213 } 3214 } 3215 3216 // At this point the agent is off and running. The next thing to happen will 3217 // either be a callback from the agent, at which point we'll process its data 3218 // for transport, or a timeout. Either way the next phase will happen in 3219 // response to the TimeoutHandler interface callbacks. 3220 addBackupTrace("invoke success"); 3221 return BackupTransport.TRANSPORT_OK; 3222 } 3223 3224 public void failAgent(IBackupAgent agent, String message) { 3225 try { 3226 agent.fail(message); 3227 } catch (Exception e) { 3228 Slog.w(TAG, "Error conveying failure to " + mCurrentPackage.packageName); 3229 } 3230 } 3231 3232 // SHA-1 a byte array and return the result in hex 3233 private String SHA1Checksum(byte[] input) { 3234 final byte[] checksum; 3235 try { 3236 MessageDigest md = MessageDigest.getInstance("SHA-1"); 3237 checksum = md.digest(input); 3238 } catch (NoSuchAlgorithmException e) { 3239 Slog.e(TAG, "Unable to use SHA-1!"); 3240 return "00"; 3241 } 3242 3243 StringBuffer sb = new StringBuffer(checksum.length * 2); 3244 for (int i = 0; i < checksum.length; i++) { 3245 sb.append(Integer.toHexString(checksum[i])); 3246 } 3247 return sb.toString(); 3248 } 3249 3250 private void writeWidgetPayloadIfAppropriate(FileDescriptor fd, String pkgName) 3251 throws IOException { 3252 // TODO: http://b/22388012 3253 byte[] widgetState = AppWidgetBackupBridge.getWidgetState(pkgName, 3254 UserHandle.USER_SYSTEM); 3255 // has the widget state changed since last time? 3256 final File widgetFile = new File(mStateDir, pkgName + "_widget"); 3257 final boolean priorStateExists = widgetFile.exists(); 3258 3259 if (MORE_DEBUG) { 3260 if (priorStateExists || widgetState != null) { 3261 Slog.i(TAG, "Checking widget update: state=" + (widgetState != null) 3262 + " prior=" + priorStateExists); 3263 } 3264 } 3265 3266 if (!priorStateExists && widgetState == null) { 3267 // no prior state, no new state => nothing to do 3268 return; 3269 } 3270 3271 // if the new state is not null, we might need to compare checksums to 3272 // determine whether to update the widget blob in the archive. If the 3273 // widget state *is* null, we know a priori at this point that we simply 3274 // need to commit a deletion for it. 3275 String newChecksum = null; 3276 if (widgetState != null) { 3277 newChecksum = SHA1Checksum(widgetState); 3278 if (priorStateExists) { 3279 final String priorChecksum; 3280 try ( 3281 FileInputStream fin = new FileInputStream(widgetFile); 3282 DataInputStream in = new DataInputStream(fin) 3283 ) { 3284 priorChecksum = in.readUTF(); 3285 } 3286 if (Objects.equals(newChecksum, priorChecksum)) { 3287 // Same checksum => no state change => don't rewrite the widget data 3288 return; 3289 } 3290 } 3291 } // else widget state *became* empty, so we need to commit a deletion 3292 3293 BackupDataOutput out = new BackupDataOutput(fd); 3294 if (widgetState != null) { 3295 try ( 3296 FileOutputStream fout = new FileOutputStream(widgetFile); 3297 DataOutputStream stateOut = new DataOutputStream(fout) 3298 ) { 3299 stateOut.writeUTF(newChecksum); 3300 } 3301 3302 out.writeEntityHeader(KEY_WIDGET_STATE, widgetState.length); 3303 out.writeEntityData(widgetState, widgetState.length); 3304 } else { 3305 // Widget state for this app has been removed; commit a deletion 3306 out.writeEntityHeader(KEY_WIDGET_STATE, -1); 3307 widgetFile.delete(); 3308 } 3309 } 3310 3311 @Override 3312 @GuardedBy("mCancelLock") 3313 public void operationComplete(long unusedResult) { 3314 removeOperation(mEphemeralOpToken); 3315 synchronized (mCancelLock) { 3316 // The agent reported back to us! 3317 if (mFinished) { 3318 Slog.d(TAG, "operationComplete received after task finished."); 3319 return; 3320 } 3321 3322 if (mBackupData == null) { 3323 // This callback was racing with our timeout, so we've cleaned up the 3324 // agent state already and are on to the next thing. We have nothing 3325 // further to do here: agent state having been cleared means that we've 3326 // initiated the appropriate next operation. 3327 final String pkg = (mCurrentPackage != null) 3328 ? mCurrentPackage.packageName : "[none]"; 3329 if (MORE_DEBUG) { 3330 Slog.i(TAG, "Callback after agent teardown: " + pkg); 3331 } 3332 addBackupTrace("late opComplete; curPkg = " + pkg); 3333 return; 3334 } 3335 3336 final String pkgName = mCurrentPackage.packageName; 3337 final long filepos = mBackupDataName.length(); 3338 FileDescriptor fd = mBackupData.getFileDescriptor(); 3339 try { 3340 // If it's a 3rd party app, see whether they wrote any protected keys 3341 // and complain mightily if they are attempting shenanigans. 3342 if (mCurrentPackage.applicationInfo != null && 3343 (mCurrentPackage.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) 3344 == 0) { 3345 ParcelFileDescriptor readFd = ParcelFileDescriptor.open(mBackupDataName, 3346 ParcelFileDescriptor.MODE_READ_ONLY); 3347 BackupDataInput in = new BackupDataInput(readFd.getFileDescriptor()); 3348 try { 3349 while (in.readNextHeader()) { 3350 final String key = in.getKey(); 3351 if (key != null && key.charAt(0) >= 0xff00) { 3352 // Not okay: crash them and bail. 3353 failAgent(mAgentBinder, "Illegal backup key: " + key); 3354 addBackupTrace("illegal key " + key + " from " + pkgName); 3355 EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, pkgName, 3356 "bad key"); 3357 mMonitor = monitorEvent(mMonitor, 3358 BackupManagerMonitor.LOG_EVENT_ID_ILLEGAL_KEY, 3359 mCurrentPackage, 3360 BackupManagerMonitor 3361 .LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, 3362 putMonitoringExtra(null, 3363 BackupManagerMonitor.EXTRA_LOG_ILLEGAL_KEY, 3364 key)); 3365 mBackupHandler.removeMessages(MSG_BACKUP_OPERATION_TIMEOUT); 3366 sendBackupOnPackageResult(mObserver, pkgName, 3367 BackupManager.ERROR_AGENT_FAILURE); 3368 errorCleanup(); 3369 // agentErrorCleanup() implicitly executes next state properly 3370 return; 3371 } 3372 in.skipEntityData(); 3373 } 3374 } finally { 3375 if (readFd != null) { 3376 readFd.close(); 3377 } 3378 } 3379 } 3380 3381 // Piggyback the widget state payload, if any 3382 writeWidgetPayloadIfAppropriate(fd, pkgName); 3383 } catch (IOException e) { 3384 // Hard disk error; recovery/failure policy TBD. For now roll back, 3385 // but we may want to consider this a transport-level failure (i.e. 3386 // we're in such a bad state that we can't contemplate doing backup 3387 // operations any more during this pass). 3388 Slog.w(TAG, "Unable to save widget state for " + pkgName); 3389 try { 3390 Os.ftruncate(fd, filepos); 3391 } catch (ErrnoException ee) { 3392 Slog.w(TAG, "Unable to roll back!"); 3393 } 3394 } 3395 3396 // Spin the data off to the transport and proceed with the next stage. 3397 if (MORE_DEBUG) Slog.v(TAG, "operationComplete(): sending data to transport for " 3398 + pkgName); 3399 mBackupHandler.removeMessages(MSG_BACKUP_OPERATION_TIMEOUT); 3400 clearAgentState(); 3401 addBackupTrace("operation complete"); 3402 3403 ParcelFileDescriptor backupData = null; 3404 mStatus = BackupTransport.TRANSPORT_OK; 3405 long size = 0; 3406 try { 3407 size = mBackupDataName.length(); 3408 if (size > 0) { 3409 if (mStatus == BackupTransport.TRANSPORT_OK) { 3410 backupData = ParcelFileDescriptor.open(mBackupDataName, 3411 ParcelFileDescriptor.MODE_READ_ONLY); 3412 addBackupTrace("sending data to transport"); 3413 int flags = mUserInitiated ? BackupTransport.FLAG_USER_INITIATED : 0; 3414 mStatus = mTransport.performBackup(mCurrentPackage, backupData, flags); 3415 } 3416 3417 // TODO - We call finishBackup() for each application backed up, because 3418 // we need to know now whether it succeeded or failed. Instead, we should 3419 // hold off on finishBackup() until the end, which implies holding off on 3420 // renaming *all* the output state files (see below) until that happens. 3421 3422 addBackupTrace("data delivered: " + mStatus); 3423 if (mStatus == BackupTransport.TRANSPORT_OK) { 3424 addBackupTrace("finishing op on transport"); 3425 mStatus = mTransport.finishBackup(); 3426 addBackupTrace("finished: " + mStatus); 3427 } else if (mStatus == BackupTransport.TRANSPORT_PACKAGE_REJECTED) { 3428 addBackupTrace("transport rejected package"); 3429 } 3430 } else { 3431 if (MORE_DEBUG) Slog.i(TAG, 3432 "no backup data written; not calling transport"); 3433 addBackupTrace("no data to send"); 3434 mMonitor = monitorEvent(mMonitor, 3435 BackupManagerMonitor.LOG_EVENT_ID_NO_DATA_TO_SEND, 3436 mCurrentPackage, 3437 BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, 3438 null); 3439 } 3440 3441 if (mStatus == BackupTransport.TRANSPORT_OK) { 3442 // After successful transport, delete the now-stale data 3443 // and juggle the files so that next time we supply the agent 3444 // with the new state file it just created. 3445 mBackupDataName.delete(); 3446 mNewStateName.renameTo(mSavedStateName); 3447 sendBackupOnPackageResult(mObserver, pkgName, BackupManager.SUCCESS); 3448 EventLog.writeEvent(EventLogTags.BACKUP_PACKAGE, pkgName, size); 3449 logBackupComplete(pkgName); 3450 } else if (mStatus == BackupTransport.TRANSPORT_PACKAGE_REJECTED) { 3451 // The transport has rejected backup of this specific package. Roll it 3452 // back but proceed with running the rest of the queue. 3453 mBackupDataName.delete(); 3454 mNewStateName.delete(); 3455 sendBackupOnPackageResult(mObserver, pkgName, 3456 BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED); 3457 EventLogTags.writeBackupAgentFailure(pkgName, "Transport rejected"); 3458 } else if (mStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) { 3459 sendBackupOnPackageResult(mObserver, pkgName, 3460 BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED); 3461 EventLog.writeEvent(EventLogTags.BACKUP_QUOTA_EXCEEDED, pkgName); 3462 } else { 3463 // Actual transport-level failure to communicate the data to the backend 3464 sendBackupOnPackageResult(mObserver, pkgName, 3465 BackupManager.ERROR_TRANSPORT_ABORTED); 3466 EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, pkgName); 3467 } 3468 } catch (Exception e) { 3469 sendBackupOnPackageResult(mObserver, pkgName, 3470 BackupManager.ERROR_TRANSPORT_ABORTED); 3471 Slog.e(TAG, "Transport error backing up " + pkgName, e); 3472 EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, pkgName); 3473 mStatus = BackupTransport.TRANSPORT_ERROR; 3474 } finally { 3475 try { 3476 if (backupData != null) backupData.close(); 3477 } catch (IOException e) { 3478 } 3479 } 3480 3481 final BackupState nextState; 3482 if (mStatus == BackupTransport.TRANSPORT_OK 3483 || mStatus == BackupTransport.TRANSPORT_PACKAGE_REJECTED) { 3484 // Success or single-package rejection. Proceed with the next app if any, 3485 // otherwise we're done. 3486 nextState = (mQueue.isEmpty()) ? BackupState.FINAL : BackupState.RUNNING_QUEUE; 3487 } else if (mStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) { 3488 if (MORE_DEBUG) { 3489 Slog.d(TAG, "Package " + mCurrentPackage.packageName + 3490 " hit quota limit on k/v backup"); 3491 } 3492 if (mAgentBinder != null) { 3493 try { 3494 long quota = mTransport.getBackupQuota(mCurrentPackage.packageName, 3495 false); 3496 mAgentBinder.doQuotaExceeded(size, quota); 3497 } catch (Exception e) { 3498 Slog.e(TAG, "Unable to notify about quota exceeded: " + e.getMessage()); 3499 } 3500 } 3501 nextState = (mQueue.isEmpty()) ? BackupState.FINAL : BackupState.RUNNING_QUEUE; 3502 } else { 3503 // Any other error here indicates a transport-level failure. That means 3504 // we need to halt everything and reschedule everything for next time. 3505 revertAndEndBackup(); 3506 nextState = BackupState.FINAL; 3507 } 3508 3509 executeNextState(nextState); 3510 } 3511 } 3512 3513 3514 @Override 3515 @GuardedBy("mCancelLock") 3516 public void handleCancel(boolean cancelAll) { 3517 removeOperation(mEphemeralOpToken); 3518 synchronized (mCancelLock) { 3519 if (mFinished) { 3520 // We have already cancelled this operation. 3521 if (MORE_DEBUG) { 3522 Slog.d(TAG, "Ignoring stale cancel. cancelAll=" + cancelAll); 3523 } 3524 return; 3525 } 3526 mCancelAll = cancelAll; 3527 // Whoops, the current agent timed out running doBackup(). Tidy up and restage 3528 // it for the next time we run a backup pass. 3529 // !!! TODO: keep track of failure counts per agent, and blacklist those which 3530 // fail repeatedly (i.e. have proved themselves to be buggy). 3531 Slog.e(TAG, "Cancel backing up " + mCurrentPackage.packageName); 3532 EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, mCurrentPackage.packageName); 3533 mMonitor = monitorEvent(mMonitor, 3534 BackupManagerMonitor.LOG_EVENT_ID_KEY_VALUE_BACKUP_CANCEL, 3535 mCurrentPackage, BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT, 3536 putMonitoringExtra(null, BackupManagerMonitor.EXTRA_LOG_CANCEL_ALL, 3537 mCancelAll)); 3538 addBackupTrace( 3539 "cancel of " + mCurrentPackage.packageName + ", cancelAll=" + cancelAll); 3540 errorCleanup(); 3541 if (!cancelAll) { 3542 executeNextState( 3543 mQueue.isEmpty() ? BackupState.FINAL : BackupState.RUNNING_QUEUE); 3544 dataChangedImpl(mCurrentPackage.packageName); 3545 } else { 3546 finalizeBackup(); 3547 } 3548 } 3549 } 3550 3551 void revertAndEndBackup() { 3552 if (MORE_DEBUG) Slog.i(TAG, "Reverting backup queue - restaging everything"); 3553 addBackupTrace("transport error; reverting"); 3554 3555 // We want to reset the backup schedule based on whatever the transport suggests 3556 // by way of retry/backoff time. 3557 long delay; 3558 try { 3559 delay = mTransport.requestBackupTime(); 3560 } catch (Exception e) { 3561 Slog.w(TAG, "Unable to contact transport for recommended backoff: " + e.getMessage()); 3562 delay = 0; // use the scheduler's default 3563 } 3564 KeyValueBackupJob.schedule(mContext, delay); 3565 3566 for (BackupRequest request : mOriginalQueue) { 3567 dataChangedImpl(request.packageName); 3568 } 3569 3570 } 3571 3572 void errorCleanup() { 3573 mBackupDataName.delete(); 3574 mNewStateName.delete(); 3575 clearAgentState(); 3576 } 3577 3578 // Cleanup common to both success and failure cases 3579 void clearAgentState() { 3580 try { if (mSavedState != null) mSavedState.close(); } catch (IOException e) {} 3581 try { if (mBackupData != null) mBackupData.close(); } catch (IOException e) {} 3582 try { if (mNewState != null) mNewState.close(); } catch (IOException e) {} 3583 synchronized (mCurrentOpLock) { 3584 // Current-operation callback handling requires the validity of these various 3585 // bits of internal state as an invariant of the operation still being live. 3586 // This means we make sure to clear all of the state in unison inside the lock. 3587 mCurrentOperations.remove(mEphemeralOpToken); 3588 mSavedState = mBackupData = mNewState = null; 3589 } 3590 3591 // If this was a pseudopackage there's no associated Activity Manager state 3592 if (mCurrentPackage.applicationInfo != null) { 3593 addBackupTrace("unbinding " + mCurrentPackage.packageName); 3594 try { // unbind even on timeout, just in case 3595 mActivityManager.unbindBackupAgent(mCurrentPackage.applicationInfo); 3596 } catch (RemoteException e) { /* can't happen; activity manager is local */ } 3597 } 3598 } 3599 3600 void executeNextState(BackupState nextState) { 3601 if (MORE_DEBUG) Slog.i(TAG, " => executing next step on " 3602 + this + " nextState=" + nextState); 3603 addBackupTrace("executeNextState => " + nextState); 3604 mCurrentState = nextState; 3605 Message msg = mBackupHandler.obtainMessage(MSG_BACKUP_RESTORE_STEP, this); 3606 mBackupHandler.sendMessage(msg); 3607 } 3608 } 3609 3610 private boolean isBackupOperationInProgress() { 3611 synchronized (mCurrentOpLock) { 3612 for (int i = 0; i < mCurrentOperations.size(); i++) { 3613 Operation op = mCurrentOperations.valueAt(i); 3614 if (op.type == OP_TYPE_BACKUP && op.state == OP_PENDING) { 3615 return true; 3616 } 3617 } 3618 } 3619 return false; 3620 } 3621 3622 3623 // ----- Full backup/restore to a file/socket ----- 3624 3625 class FullBackupObbConnection implements ServiceConnection { 3626 volatile IObbBackupService mService; 3627 3628 FullBackupObbConnection() { 3629 mService = null; 3630 } 3631 3632 public void establish() { 3633 if (MORE_DEBUG) Slog.i(TAG, "Initiating bind of OBB service on " + this); 3634 Intent obbIntent = new Intent().setComponent(new ComponentName( 3635 "com.android.sharedstoragebackup", 3636 "com.android.sharedstoragebackup.ObbBackupService")); 3637 BackupManagerService.this.mContext.bindServiceAsUser( 3638 obbIntent, this, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM); 3639 } 3640 3641 public void tearDown() { 3642 BackupManagerService.this.mContext.unbindService(this); 3643 } 3644 3645 public boolean backupObbs(PackageInfo pkg, OutputStream out) { 3646 boolean success = false; 3647 waitForConnection(); 3648 3649 ParcelFileDescriptor[] pipes = null; 3650 try { 3651 pipes = ParcelFileDescriptor.createPipe(); 3652 int token = generateToken(); 3653 prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL, 3654 null, OP_TYPE_BACKUP_WAIT); 3655 mService.backupObbs(pkg.packageName, pipes[1], token, mBackupManagerBinder); 3656 routeSocketDataToOutput(pipes[0], out); 3657 success = waitUntilOperationComplete(token); 3658 } catch (Exception e) { 3659 Slog.w(TAG, "Unable to back up OBBs for " + pkg, e); 3660 } finally { 3661 try { 3662 out.flush(); 3663 if (pipes != null) { 3664 if (pipes[0] != null) pipes[0].close(); 3665 if (pipes[1] != null) pipes[1].close(); 3666 } 3667 } catch (IOException e) { 3668 Slog.w(TAG, "I/O error closing down OBB backup", e); 3669 } 3670 } 3671 return success; 3672 } 3673 3674 public void restoreObbFile(String pkgName, ParcelFileDescriptor data, 3675 long fileSize, int type, String path, long mode, long mtime, 3676 int token, IBackupManager callbackBinder) { 3677 waitForConnection(); 3678 3679 try { 3680 mService.restoreObbFile(pkgName, data, fileSize, type, path, mode, mtime, 3681 token, callbackBinder); 3682 } catch (Exception e) { 3683 Slog.w(TAG, "Unable to restore OBBs for " + pkgName, e); 3684 } 3685 } 3686 3687 private void waitForConnection() { 3688 synchronized (this) { 3689 while (mService == null) { 3690 if (MORE_DEBUG) Slog.i(TAG, "...waiting for OBB service binding..."); 3691 try { 3692 this.wait(); 3693 } catch (InterruptedException e) { /* never interrupted */ } 3694 } 3695 if (MORE_DEBUG) Slog.i(TAG, "Connected to OBB service; continuing"); 3696 } 3697 } 3698 3699 @Override 3700 public void onServiceConnected(ComponentName name, IBinder service) { 3701 synchronized (this) { 3702 mService = IObbBackupService.Stub.asInterface(service); 3703 if (MORE_DEBUG) Slog.i(TAG, "OBB service connection " + mService 3704 + " connected on " + this); 3705 this.notifyAll(); 3706 } 3707 } 3708 3709 @Override 3710 public void onServiceDisconnected(ComponentName name) { 3711 synchronized (this) { 3712 mService = null; 3713 if (MORE_DEBUG) Slog.i(TAG, "OBB service connection disconnected on " + this); 3714 this.notifyAll(); 3715 } 3716 } 3717 3718 } 3719 3720 private void routeSocketDataToOutput(ParcelFileDescriptor inPipe, OutputStream out) 3721 throws IOException { 3722 // We do not take close() responsibility for the pipe FD 3723 FileInputStream raw = new FileInputStream(inPipe.getFileDescriptor()); 3724 DataInputStream in = new DataInputStream(raw); 3725 3726 byte[] buffer = new byte[32 * 1024]; 3727 int chunkTotal; 3728 while ((chunkTotal = in.readInt()) > 0) { 3729 while (chunkTotal > 0) { 3730 int toRead = (chunkTotal > buffer.length) ? buffer.length : chunkTotal; 3731 int nRead = in.read(buffer, 0, toRead); 3732 out.write(buffer, 0, nRead); 3733 chunkTotal -= nRead; 3734 } 3735 } 3736 } 3737 3738 void tearDownAgentAndKill(ApplicationInfo app) { 3739 if (app == null) { 3740 // Null means the system package, so just quietly move on. :) 3741 return; 3742 } 3743 3744 try { 3745 // unbind and tidy up even on timeout or failure, just in case 3746 mActivityManager.unbindBackupAgent(app); 3747 3748 // The agent was running with a stub Application object, so shut it down. 3749 // !!! We hardcode the confirmation UI's package name here rather than use a 3750 // manifest flag! TODO something less direct. 3751 if (app.uid >= Process.FIRST_APPLICATION_UID 3752 && !app.packageName.equals("com.android.backupconfirm")) { 3753 if (MORE_DEBUG) Slog.d(TAG, "Killing agent host process"); 3754 mActivityManager.killApplicationProcess(app.processName, app.uid); 3755 } else { 3756 if (MORE_DEBUG) Slog.d(TAG, "Not killing after operation: " + app.processName); 3757 } 3758 } catch (RemoteException e) { 3759 Slog.d(TAG, "Lost app trying to shut down"); 3760 } 3761 } 3762 3763 // Core logic for performing one package's full backup, gathering the tarball from the 3764 // application and emitting it to the designated OutputStream. 3765 3766 // Callout from the engine to an interested participant that might need to communicate 3767 // with the agent prior to asking it to move data 3768 interface FullBackupPreflight { 3769 /** 3770 * Perform the preflight operation necessary for the given package. 3771 * @param pkg The name of the package being proposed for full-data backup 3772 * @param agent Live BackupAgent binding to the target app's agent 3773 * @return BackupTransport.TRANSPORT_OK to proceed with the backup operation, 3774 * or one of the other BackupTransport.* error codes as appropriate 3775 */ 3776 int preflightFullBackup(PackageInfo pkg, IBackupAgent agent); 3777 3778 long getExpectedSizeOrErrorCode(); 3779 }; 3780 3781 class FullBackupEngine { 3782 OutputStream mOutput; 3783 FullBackupPreflight mPreflightHook; 3784 BackupRestoreTask mTimeoutMonitor; 3785 IBackupAgent mAgent; 3786 File mFilesDir; 3787 File mManifestFile; 3788 File mMetadataFile; 3789 boolean mIncludeApks; 3790 PackageInfo mPkg; 3791 private final long mQuota; 3792 private final int mOpToken; 3793 3794 class FullBackupRunner implements Runnable { 3795 PackageInfo mPackage; 3796 byte[] mWidgetData; 3797 IBackupAgent mAgent; 3798 ParcelFileDescriptor mPipe; 3799 int mToken; 3800 boolean mSendApk; 3801 boolean mWriteManifest; 3802 3803 FullBackupRunner(PackageInfo pack, IBackupAgent agent, ParcelFileDescriptor pipe, 3804 int token, boolean sendApk, boolean writeManifest, byte[] widgetData) 3805 throws IOException { 3806 mPackage = pack; 3807 mWidgetData = widgetData; 3808 mAgent = agent; 3809 mPipe = ParcelFileDescriptor.dup(pipe.getFileDescriptor()); 3810 mToken = token; 3811 mSendApk = sendApk; 3812 mWriteManifest = writeManifest; 3813 } 3814 3815 @Override 3816 public void run() { 3817 try { 3818 FullBackupDataOutput output = new FullBackupDataOutput(mPipe); 3819 3820 if (mWriteManifest) { 3821 final boolean writeWidgetData = mWidgetData != null; 3822 if (MORE_DEBUG) Slog.d(TAG, "Writing manifest for " + mPackage.packageName); 3823 writeAppManifest(mPackage, mManifestFile, mSendApk, writeWidgetData); 3824 FullBackup.backupToTar(mPackage.packageName, null, null, 3825 mFilesDir.getAbsolutePath(), 3826 mManifestFile.getAbsolutePath(), 3827 output); 3828 mManifestFile.delete(); 3829 3830 // We only need to write a metadata file if we have widget data to stash 3831 if (writeWidgetData) { 3832 writeMetadata(mPackage, mMetadataFile, mWidgetData); 3833 FullBackup.backupToTar(mPackage.packageName, null, null, 3834 mFilesDir.getAbsolutePath(), 3835 mMetadataFile.getAbsolutePath(), 3836 output); 3837 mMetadataFile.delete(); 3838 } 3839 } 3840 3841 if (mSendApk) { 3842 writeApkToBackup(mPackage, output); 3843 } 3844 3845 if (DEBUG) Slog.d(TAG, "Calling doFullBackup() on " + mPackage.packageName); 3846 prepareOperationTimeout(mToken, TIMEOUT_FULL_BACKUP_INTERVAL, 3847 mTimeoutMonitor /* in parent class */, OP_TYPE_BACKUP_WAIT); 3848 mAgent.doFullBackup(mPipe, mQuota, mToken, mBackupManagerBinder); 3849 } catch (IOException e) { 3850 Slog.e(TAG, "Error running full backup for " + mPackage.packageName); 3851 } catch (RemoteException e) { 3852 Slog.e(TAG, "Remote agent vanished during full backup of " 3853 + mPackage.packageName); 3854 } finally { 3855 try { 3856 mPipe.close(); 3857 } catch (IOException e) {} 3858 } 3859 } 3860 } 3861 3862 FullBackupEngine(OutputStream output, FullBackupPreflight preflightHook, PackageInfo pkg, 3863 boolean alsoApks, BackupRestoreTask timeoutMonitor, long quota, int opToken) { 3864 mOutput = output; 3865 mPreflightHook = preflightHook; 3866 mPkg = pkg; 3867 mIncludeApks = alsoApks; 3868 mTimeoutMonitor = timeoutMonitor; 3869 mFilesDir = new File("/data/system"); 3870 mManifestFile = new File(mFilesDir, BACKUP_MANIFEST_FILENAME); 3871 mMetadataFile = new File(mFilesDir, BACKUP_METADATA_FILENAME); 3872 mQuota = quota; 3873 mOpToken = opToken; 3874 } 3875 3876 public int preflightCheck() throws RemoteException { 3877 if (mPreflightHook == null) { 3878 if (MORE_DEBUG) { 3879 Slog.v(TAG, "No preflight check"); 3880 } 3881 return BackupTransport.TRANSPORT_OK; 3882 } 3883 if (initializeAgent()) { 3884 int result = mPreflightHook.preflightFullBackup(mPkg, mAgent); 3885 if (MORE_DEBUG) { 3886 Slog.v(TAG, "preflight returned " + result); 3887 } 3888 return result; 3889 } else { 3890 Slog.w(TAG, "Unable to bind to full agent for " + mPkg.packageName); 3891 return BackupTransport.AGENT_ERROR; 3892 } 3893 } 3894 3895 public int backupOnePackage() throws RemoteException { 3896 int result = BackupTransport.AGENT_ERROR; 3897 3898 if (initializeAgent()) { 3899 ParcelFileDescriptor[] pipes = null; 3900 try { 3901 pipes = ParcelFileDescriptor.createPipe(); 3902 3903 ApplicationInfo app = mPkg.applicationInfo; 3904 final boolean isSharedStorage = 3905 mPkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE); 3906 final boolean sendApk = mIncludeApks 3907 && !isSharedStorage 3908 && ((app.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) == 0) 3909 && ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0 || 3910 (app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0); 3911 3912 // TODO: http://b/22388012 3913 byte[] widgetBlob = AppWidgetBackupBridge.getWidgetState(mPkg.packageName, 3914 UserHandle.USER_SYSTEM); 3915 3916 FullBackupRunner runner = new FullBackupRunner(mPkg, mAgent, pipes[1], 3917 mOpToken, sendApk, !isSharedStorage, widgetBlob); 3918 pipes[1].close(); // the runner has dup'd it 3919 pipes[1] = null; 3920 Thread t = new Thread(runner, "app-data-runner"); 3921 t.start(); 3922 3923 // Now pull data from the app and stuff it into the output 3924 routeSocketDataToOutput(pipes[0], mOutput); 3925 3926 if (!waitUntilOperationComplete(mOpToken)) { 3927 Slog.e(TAG, "Full backup failed on package " + mPkg.packageName); 3928 } else { 3929 if (MORE_DEBUG) { 3930 Slog.d(TAG, "Full package backup success: " + mPkg.packageName); 3931 } 3932 result = BackupTransport.TRANSPORT_OK; 3933 } 3934 } catch (IOException e) { 3935 Slog.e(TAG, "Error backing up " + mPkg.packageName + ": " + e.getMessage()); 3936 result = BackupTransport.AGENT_ERROR; 3937 } finally { 3938 try { 3939 // flush after every package 3940 mOutput.flush(); 3941 if (pipes != null) { 3942 if (pipes[0] != null) pipes[0].close(); 3943 if (pipes[1] != null) pipes[1].close(); 3944 } 3945 } catch (IOException e) { 3946 Slog.w(TAG, "Error bringing down backup stack"); 3947 result = BackupTransport.TRANSPORT_ERROR; 3948 } 3949 } 3950 } else { 3951 Slog.w(TAG, "Unable to bind to full agent for " + mPkg.packageName); 3952 } 3953 tearDown(); 3954 return result; 3955 } 3956 3957 public void sendQuotaExceeded(final long backupDataBytes, final long quotaBytes) { 3958 if (initializeAgent()) { 3959 try { 3960 mAgent.doQuotaExceeded(backupDataBytes, quotaBytes); 3961 } catch (RemoteException e) { 3962 Slog.e(TAG, "Remote exception while telling agent about quota exceeded"); 3963 } 3964 } 3965 } 3966 3967 private boolean initializeAgent() { 3968 if (mAgent == null) { 3969 if (MORE_DEBUG) { 3970 Slog.d(TAG, "Binding to full backup agent : " + mPkg.packageName); 3971 } 3972 mAgent = bindToAgentSynchronous(mPkg.applicationInfo, 3973 ApplicationThreadConstants.BACKUP_MODE_FULL); 3974 } 3975 return mAgent != null; 3976 } 3977 3978 private void writeApkToBackup(PackageInfo pkg, FullBackupDataOutput output) { 3979 // Forward-locked apps, system-bundled .apks, etc are filtered out before we get here 3980 // TODO: handle backing up split APKs 3981 final String appSourceDir = pkg.applicationInfo.getBaseCodePath(); 3982 final String apkDir = new File(appSourceDir).getParent(); 3983 FullBackup.backupToTar(pkg.packageName, FullBackup.APK_TREE_TOKEN, null, 3984 apkDir, appSourceDir, output); 3985 3986 // TODO: migrate this to SharedStorageBackup, since AID_SYSTEM 3987 // doesn't have access to external storage. 3988 3989 // Save associated .obb content if it exists and we did save the apk 3990 // check for .obb and save those too 3991 // TODO: http://b/22388012 3992 final UserEnvironment userEnv = new UserEnvironment(UserHandle.USER_SYSTEM); 3993 final File obbDir = userEnv.buildExternalStorageAppObbDirs(pkg.packageName)[0]; 3994 if (obbDir != null) { 3995 if (MORE_DEBUG) Log.i(TAG, "obb dir: " + obbDir.getAbsolutePath()); 3996 File[] obbFiles = obbDir.listFiles(); 3997 if (obbFiles != null) { 3998 final String obbDirName = obbDir.getAbsolutePath(); 3999 for (File obb : obbFiles) { 4000 FullBackup.backupToTar(pkg.packageName, FullBackup.OBB_TREE_TOKEN, null, 4001 obbDirName, obb.getAbsolutePath(), output); 4002 } 4003 } 4004 } 4005 } 4006 4007 private void writeAppManifest(PackageInfo pkg, File manifestFile, 4008 boolean withApk, boolean withWidgets) throws IOException { 4009 // Manifest format. All data are strings ending in LF: 4010 // BACKUP_MANIFEST_VERSION, currently 1 4011 // 4012 // Version 1: 4013 // package name 4014 // package's versionCode 4015 // platform versionCode 4016 // getInstallerPackageName() for this package (maybe empty) 4017 // boolean: "1" if archive includes .apk; any other string means not 4018 // number of signatures == N 4019 // N*: signature byte array in ascii format per Signature.toCharsString() 4020 StringBuilder builder = new StringBuilder(4096); 4021 StringBuilderPrinter printer = new StringBuilderPrinter(builder); 4022 4023 printer.println(Integer.toString(BACKUP_MANIFEST_VERSION)); 4024 printer.println(pkg.packageName); 4025 printer.println(Integer.toString(pkg.versionCode)); 4026 printer.println(Integer.toString(Build.VERSION.SDK_INT)); 4027 4028 String installerName = mPackageManager.getInstallerPackageName(pkg.packageName); 4029 printer.println((installerName != null) ? installerName : ""); 4030 4031 printer.println(withApk ? "1" : "0"); 4032 if (pkg.signatures == null) { 4033 printer.println("0"); 4034 } else { 4035 printer.println(Integer.toString(pkg.signatures.length)); 4036 for (Signature sig : pkg.signatures) { 4037 printer.println(sig.toCharsString()); 4038 } 4039 } 4040 4041 FileOutputStream outstream = new FileOutputStream(manifestFile); 4042 outstream.write(builder.toString().getBytes()); 4043 outstream.close(); 4044 4045 // We want the manifest block in the archive stream to be idempotent: 4046 // each time we generate a backup stream for the app, we want the manifest 4047 // block to be identical. The underlying tar mechanism sees it as a file, 4048 // though, and will propagate its mtime, causing the tar header to vary. 4049 // Avoid this problem by pinning the mtime to zero. 4050 manifestFile.setLastModified(0); 4051 } 4052 4053 // Widget metadata format. All header entries are strings ending in LF: 4054 // 4055 // Version 1 header: 4056 // BACKUP_METADATA_VERSION, currently "1" 4057 // package name 4058 // 4059 // File data (all integers are binary in network byte order) 4060 // *N: 4 : integer token identifying which metadata blob 4061 // 4 : integer size of this blob = N 4062 // N : raw bytes of this metadata blob 4063 // 4064 // Currently understood blobs (always in network byte order): 4065 // 4066 // widgets : metadata token = 0x01FFED01 (BACKUP_WIDGET_METADATA_TOKEN) 4067 // 4068 // Unrecognized blobs are *ignored*, not errors. 4069 private void writeMetadata(PackageInfo pkg, File destination, byte[] widgetData) 4070 throws IOException { 4071 StringBuilder b = new StringBuilder(512); 4072 StringBuilderPrinter printer = new StringBuilderPrinter(b); 4073 printer.println(Integer.toString(BACKUP_METADATA_VERSION)); 4074 printer.println(pkg.packageName); 4075 4076 FileOutputStream fout = new FileOutputStream(destination); 4077 BufferedOutputStream bout = new BufferedOutputStream(fout); 4078 DataOutputStream out = new DataOutputStream(bout); 4079 bout.write(b.toString().getBytes()); // bypassing DataOutputStream 4080 4081 if (widgetData != null && widgetData.length > 0) { 4082 out.writeInt(BACKUP_WIDGET_METADATA_TOKEN); 4083 out.writeInt(widgetData.length); 4084 out.write(widgetData); 4085 } 4086 bout.flush(); 4087 out.close(); 4088 4089 // As with the manifest file, guarantee idempotence of the archive metadata 4090 // for the widget block by using a fixed mtime on the transient file. 4091 destination.setLastModified(0); 4092 } 4093 4094 private void tearDown() { 4095 if (mPkg != null) { 4096 tearDownAgentAndKill(mPkg.applicationInfo); 4097 } 4098 } 4099 } 4100 4101 // Generic driver skeleton for full backup operations 4102 abstract class FullBackupTask implements Runnable { 4103 IFullBackupRestoreObserver mObserver; 4104 4105 FullBackupTask(IFullBackupRestoreObserver observer) { 4106 mObserver = observer; 4107 } 4108 4109 // wrappers for observer use 4110 final void sendStartBackup() { 4111 if (mObserver != null) { 4112 try { 4113 mObserver.onStartBackup(); 4114 } catch (RemoteException e) { 4115 Slog.w(TAG, "full backup observer went away: startBackup"); 4116 mObserver = null; 4117 } 4118 } 4119 } 4120 4121 final void sendOnBackupPackage(String name) { 4122 if (mObserver != null) { 4123 try { 4124 // TODO: use a more user-friendly name string 4125 mObserver.onBackupPackage(name); 4126 } catch (RemoteException e) { 4127 Slog.w(TAG, "full backup observer went away: backupPackage"); 4128 mObserver = null; 4129 } 4130 } 4131 } 4132 4133 final void sendEndBackup() { 4134 if (mObserver != null) { 4135 try { 4136 mObserver.onEndBackup(); 4137 } catch (RemoteException e) { 4138 Slog.w(TAG, "full backup observer went away: endBackup"); 4139 mObserver = null; 4140 } 4141 } 4142 } 4143 } 4144 4145 boolean deviceIsEncrypted() { 4146 try { 4147 return mStorageManager.getEncryptionState() 4148 != StorageManager.ENCRYPTION_STATE_NONE 4149 && mStorageManager.getPasswordType() 4150 != StorageManager.CRYPT_TYPE_DEFAULT; 4151 } catch (Exception e) { 4152 // If we can't talk to the storagemanager service we have a serious problem; fail 4153 // "secure" i.e. assuming that the device is encrypted. 4154 Slog.e(TAG, "Unable to communicate with storagemanager service: " + e.getMessage()); 4155 return true; 4156 } 4157 } 4158 4159 // Full backup task variant used for adb backup 4160 class PerformAdbBackupTask extends FullBackupTask implements BackupRestoreTask { 4161 FullBackupEngine mBackupEngine; 4162 final AtomicBoolean mLatch; 4163 4164 ParcelFileDescriptor mOutputFile; 4165 DeflaterOutputStream mDeflater; 4166 boolean mIncludeApks; 4167 boolean mIncludeObbs; 4168 boolean mIncludeShared; 4169 boolean mDoWidgets; 4170 boolean mAllApps; 4171 boolean mIncludeSystem; 4172 boolean mCompress; 4173 ArrayList<String> mPackages; 4174 PackageInfo mCurrentTarget; 4175 String mCurrentPassword; 4176 String mEncryptPassword; 4177 private final int mCurrentOpToken; 4178 4179 PerformAdbBackupTask(ParcelFileDescriptor fd, IFullBackupRestoreObserver observer, 4180 boolean includeApks, boolean includeObbs, boolean includeShared, 4181 boolean doWidgets, String curPassword, String encryptPassword, boolean doAllApps, 4182 boolean doSystem, boolean doCompress, String[] packages, AtomicBoolean latch) { 4183 super(observer); 4184 mCurrentOpToken = generateToken(); 4185 mLatch = latch; 4186 4187 mOutputFile = fd; 4188 mIncludeApks = includeApks; 4189 mIncludeObbs = includeObbs; 4190 mIncludeShared = includeShared; 4191 mDoWidgets = doWidgets; 4192 mAllApps = doAllApps; 4193 mIncludeSystem = doSystem; 4194 mPackages = (packages == null) 4195 ? new ArrayList<String>() 4196 : new ArrayList<String>(Arrays.asList(packages)); 4197 mCurrentPassword = curPassword; 4198 // when backing up, if there is a current backup password, we require that 4199 // the user use a nonempty encryption password as well. if one is supplied 4200 // in the UI we use that, but if the UI was left empty we fall back to the 4201 // current backup password (which was supplied by the user as well). 4202 if (encryptPassword == null || "".equals(encryptPassword)) { 4203 mEncryptPassword = curPassword; 4204 } else { 4205 mEncryptPassword = encryptPassword; 4206 } 4207 if (MORE_DEBUG) { 4208 Slog.w(TAG, "Encrypting backup with passphrase=" + mEncryptPassword); 4209 } 4210 mCompress = doCompress; 4211 } 4212 4213 void addPackagesToSet(TreeMap<String, PackageInfo> set, List<String> pkgNames) { 4214 for (String pkgName : pkgNames) { 4215 if (!set.containsKey(pkgName)) { 4216 try { 4217 PackageInfo info = mPackageManager.getPackageInfo(pkgName, 4218 PackageManager.GET_SIGNATURES); 4219 set.put(pkgName, info); 4220 } catch (NameNotFoundException e) { 4221 Slog.w(TAG, "Unknown package " + pkgName + ", skipping"); 4222 } 4223 } 4224 } 4225 } 4226 4227 private OutputStream emitAesBackupHeader(StringBuilder headerbuf, 4228 OutputStream ofstream) throws Exception { 4229 // User key will be used to encrypt the master key. 4230 byte[] newUserSalt = randomBytes(PBKDF2_SALT_SIZE); 4231 SecretKey userKey = buildPasswordKey(PBKDF_CURRENT, mEncryptPassword, newUserSalt, 4232 PBKDF2_HASH_ROUNDS); 4233 4234 // the master key is random for each backup 4235 byte[] masterPw = new byte[256 / 8]; 4236 mRng.nextBytes(masterPw); 4237 byte[] checksumSalt = randomBytes(PBKDF2_SALT_SIZE); 4238 4239 // primary encryption of the datastream with the random key 4240 Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding"); 4241 SecretKeySpec masterKeySpec = new SecretKeySpec(masterPw, "AES"); 4242 c.init(Cipher.ENCRYPT_MODE, masterKeySpec); 4243 OutputStream finalOutput = new CipherOutputStream(ofstream, c); 4244 4245 // line 4: name of encryption algorithm 4246 headerbuf.append(ENCRYPTION_ALGORITHM_NAME); 4247 headerbuf.append('\n'); 4248 // line 5: user password salt [hex] 4249 headerbuf.append(byteArrayToHex(newUserSalt)); 4250 headerbuf.append('\n'); 4251 // line 6: master key checksum salt [hex] 4252 headerbuf.append(byteArrayToHex(checksumSalt)); 4253 headerbuf.append('\n'); 4254 // line 7: number of PBKDF2 rounds used [decimal] 4255 headerbuf.append(PBKDF2_HASH_ROUNDS); 4256 headerbuf.append('\n'); 4257 4258 // line 8: IV of the user key [hex] 4259 Cipher mkC = Cipher.getInstance("AES/CBC/PKCS5Padding"); 4260 mkC.init(Cipher.ENCRYPT_MODE, userKey); 4261 4262 byte[] IV = mkC.getIV(); 4263 headerbuf.append(byteArrayToHex(IV)); 4264 headerbuf.append('\n'); 4265 4266 // line 9: master IV + key blob, encrypted by the user key [hex]. Blob format: 4267 // [byte] IV length = Niv 4268 // [array of Niv bytes] IV itself 4269 // [byte] master key length = Nmk 4270 // [array of Nmk bytes] master key itself 4271 // [byte] MK checksum hash length = Nck 4272 // [array of Nck bytes] master key checksum hash 4273 // 4274 // The checksum is the (master key + checksum salt), run through the 4275 // stated number of PBKDF2 rounds 4276 IV = c.getIV(); 4277 byte[] mk = masterKeySpec.getEncoded(); 4278 byte[] checksum = makeKeyChecksum(PBKDF_CURRENT, masterKeySpec.getEncoded(), 4279 checksumSalt, PBKDF2_HASH_ROUNDS); 4280 4281 ByteArrayOutputStream blob = new ByteArrayOutputStream(IV.length + mk.length 4282 + checksum.length + 3); 4283 DataOutputStream mkOut = new DataOutputStream(blob); 4284 mkOut.writeByte(IV.length); 4285 mkOut.write(IV); 4286 mkOut.writeByte(mk.length); 4287 mkOut.write(mk); 4288 mkOut.writeByte(checksum.length); 4289 mkOut.write(checksum); 4290 mkOut.flush(); 4291 byte[] encryptedMk = mkC.doFinal(blob.toByteArray()); 4292 headerbuf.append(byteArrayToHex(encryptedMk)); 4293 headerbuf.append('\n'); 4294 4295 return finalOutput; 4296 } 4297 4298 private void finalizeBackup(OutputStream out) { 4299 try { 4300 // A standard 'tar' EOF sequence: two 512-byte blocks of all zeroes. 4301 byte[] eof = new byte[512 * 2]; // newly allocated == zero filled 4302 out.write(eof); 4303 } catch (IOException e) { 4304 Slog.w(TAG, "Error attempting to finalize backup stream"); 4305 } 4306 } 4307 4308 @Override 4309 public void run() { 4310 Slog.i(TAG, "--- Performing full-dataset adb backup ---"); 4311 4312 TreeMap<String, PackageInfo> packagesToBackup = new TreeMap<String, PackageInfo>(); 4313 FullBackupObbConnection obbConnection = new FullBackupObbConnection(); 4314 obbConnection.establish(); // we'll want this later 4315 4316 sendStartBackup(); 4317 4318 // doAllApps supersedes the package set if any 4319 if (mAllApps) { 4320 List<PackageInfo> allPackages = mPackageManager.getInstalledPackages( 4321 PackageManager.GET_SIGNATURES); 4322 for (int i = 0; i < allPackages.size(); i++) { 4323 PackageInfo pkg = allPackages.get(i); 4324 // Exclude system apps if we've been asked to do so 4325 if (mIncludeSystem == true 4326 || ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0)) { 4327 packagesToBackup.put(pkg.packageName, pkg); 4328 } 4329 } 4330 } 4331 4332 // If we're doing widget state as well, ensure that we have all the involved 4333 // host & provider packages in the set 4334 if (mDoWidgets) { 4335 // TODO: http://b/22388012 4336 List<String> pkgs = 4337 AppWidgetBackupBridge.getWidgetParticipants(UserHandle.USER_SYSTEM); 4338 if (pkgs != null) { 4339 if (MORE_DEBUG) { 4340 Slog.i(TAG, "Adding widget participants to backup set:"); 4341 StringBuilder sb = new StringBuilder(128); 4342 sb.append(" "); 4343 for (String s : pkgs) { 4344 sb.append(' '); 4345 sb.append(s); 4346 } 4347 Slog.i(TAG, sb.toString()); 4348 } 4349 addPackagesToSet(packagesToBackup, pkgs); 4350 } 4351 } 4352 4353 // Now process the command line argument packages, if any. Note that explicitly- 4354 // named system-partition packages will be included even if includeSystem was 4355 // set to false. 4356 if (mPackages != null) { 4357 addPackagesToSet(packagesToBackup, mPackages); 4358 } 4359 4360 // Now we cull any inapplicable / inappropriate packages from the set. This 4361 // includes the special shared-storage agent package; we handle that one 4362 // explicitly at the end of the backup pass. 4363 Iterator<Entry<String, PackageInfo>> iter = packagesToBackup.entrySet().iterator(); 4364 while (iter.hasNext()) { 4365 PackageInfo pkg = iter.next().getValue(); 4366 if (!appIsEligibleForBackup(pkg.applicationInfo) 4367 || appIsStopped(pkg.applicationInfo) 4368 || appIsKeyValueOnly(pkg)) { 4369 iter.remove(); 4370 } 4371 } 4372 4373 // flatten the set of packages now so we can explicitly control the ordering 4374 ArrayList<PackageInfo> backupQueue = 4375 new ArrayList<PackageInfo>(packagesToBackup.values()); 4376 FileOutputStream ofstream = new FileOutputStream(mOutputFile.getFileDescriptor()); 4377 OutputStream out = null; 4378 4379 PackageInfo pkg = null; 4380 try { 4381 boolean encrypting = (mEncryptPassword != null && mEncryptPassword.length() > 0); 4382 4383 // Only allow encrypted backups of encrypted devices 4384 if (deviceIsEncrypted() && !encrypting) { 4385 Slog.e(TAG, "Unencrypted backup of encrypted device; aborting"); 4386 return; 4387 } 4388 4389 OutputStream finalOutput = ofstream; 4390 4391 // Verify that the given password matches the currently-active 4392 // backup password, if any 4393 if (!backupPasswordMatches(mCurrentPassword)) { 4394 if (DEBUG) Slog.w(TAG, "Backup password mismatch; aborting"); 4395 return; 4396 } 4397 4398 // Write the global file header. All strings are UTF-8 encoded; lines end 4399 // with a '\n' byte. Actual backup data begins immediately following the 4400 // final '\n'. 4401 // 4402 // line 1: "ANDROID BACKUP" 4403 // line 2: backup file format version, currently "2" 4404 // line 3: compressed? "0" if not compressed, "1" if compressed. 4405 // line 4: name of encryption algorithm [currently only "none" or "AES-256"] 4406 // 4407 // When line 4 is not "none", then additional header data follows: 4408 // 4409 // line 5: user password salt [hex] 4410 // line 6: master key checksum salt [hex] 4411 // line 7: number of PBKDF2 rounds to use (same for user & master) [decimal] 4412 // line 8: IV of the user key [hex] 4413 // line 9: master key blob [hex] 4414 // IV of the master key, master key itself, master key checksum hash 4415 // 4416 // The master key checksum is the master key plus its checksum salt, run through 4417 // 10k rounds of PBKDF2. This is used to verify that the user has supplied the 4418 // correct password for decrypting the archive: the master key decrypted from 4419 // the archive using the user-supplied password is also run through PBKDF2 in 4420 // this way, and if the result does not match the checksum as stored in the 4421 // archive, then we know that the user-supplied password does not match the 4422 // archive's. 4423 StringBuilder headerbuf = new StringBuilder(1024); 4424 4425 headerbuf.append(BACKUP_FILE_HEADER_MAGIC); 4426 headerbuf.append(BACKUP_FILE_VERSION); // integer, no trailing \n 4427 headerbuf.append(mCompress ? "\n1\n" : "\n0\n"); 4428 4429 try { 4430 // Set up the encryption stage if appropriate, and emit the correct header 4431 if (encrypting) { 4432 finalOutput = emitAesBackupHeader(headerbuf, finalOutput); 4433 } else { 4434 headerbuf.append("none\n"); 4435 } 4436 4437 byte[] header = headerbuf.toString().getBytes("UTF-8"); 4438 ofstream.write(header); 4439 4440 // Set up the compression stage feeding into the encryption stage (if any) 4441 if (mCompress) { 4442 Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION); 4443 finalOutput = new DeflaterOutputStream(finalOutput, deflater, true); 4444 } 4445 4446 out = finalOutput; 4447 } catch (Exception e) { 4448 // Should never happen! 4449 Slog.e(TAG, "Unable to emit archive header", e); 4450 return; 4451 } 4452 4453 // Shared storage if requested 4454 if (mIncludeShared) { 4455 try { 4456 pkg = mPackageManager.getPackageInfo(SHARED_BACKUP_AGENT_PACKAGE, 0); 4457 backupQueue.add(pkg); 4458 } catch (NameNotFoundException e) { 4459 Slog.e(TAG, "Unable to find shared-storage backup handler"); 4460 } 4461 } 4462 4463 // Now actually run the constructed backup sequence 4464 int N = backupQueue.size(); 4465 for (int i = 0; i < N; i++) { 4466 pkg = backupQueue.get(i); 4467 final boolean isSharedStorage = 4468 pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE); 4469 4470 mBackupEngine = new FullBackupEngine(out, null, pkg, mIncludeApks, this, Long.MAX_VALUE, mCurrentOpToken); 4471 sendOnBackupPackage(isSharedStorage ? "Shared storage" : pkg.packageName); 4472 4473 // Don't need to check preflight result as there is no preflight hook. 4474 mCurrentTarget = pkg; 4475 mBackupEngine.backupOnePackage(); 4476 4477 // after the app's agent runs to handle its private filesystem 4478 // contents, back up any OBB content it has on its behalf. 4479 if (mIncludeObbs) { 4480 boolean obbOkay = obbConnection.backupObbs(pkg, out); 4481 if (!obbOkay) { 4482 throw new RuntimeException("Failure writing OBB stack for " + pkg); 4483 } 4484 } 4485 } 4486 4487 // Done! 4488 finalizeBackup(out); 4489 } catch (RemoteException e) { 4490 Slog.e(TAG, "App died during full backup"); 4491 } catch (Exception e) { 4492 Slog.e(TAG, "Internal exception during full backup", e); 4493 } finally { 4494 try { 4495 if (out != null) { 4496 out.flush(); 4497 out.close(); 4498 } 4499 mOutputFile.close(); 4500 } catch (IOException e) { 4501 /* nothing we can do about this */ 4502 } 4503 synchronized (mLatch) { 4504 mLatch.set(true); 4505 mLatch.notifyAll(); 4506 } 4507 sendEndBackup(); 4508 obbConnection.tearDown(); 4509 if (DEBUG) Slog.d(TAG, "Full backup pass complete."); 4510 mWakelock.release(); 4511 } 4512 } 4513 4514 // BackupRestoreTask methods, used for timeout handling 4515 @Override 4516 public void execute() { 4517 // Unused 4518 } 4519 4520 @Override 4521 public void operationComplete(long result) { 4522 // Unused 4523 } 4524 4525 @Override 4526 public void handleCancel(boolean cancelAll) { 4527 final PackageInfo target = mCurrentTarget; 4528 if (DEBUG) { 4529 Slog.w(TAG, "adb backup cancel of " + target); 4530 } 4531 if (target != null) { 4532 tearDownAgentAndKill(mCurrentTarget.applicationInfo); 4533 } 4534 removeOperation(mCurrentOpToken); 4535 } 4536 } 4537 4538 /** 4539 * Full backup task extension used for transport-oriented operation. 4540 * 4541 * Flow: 4542 * For each requested package: 4543 * - Spin off a new SinglePackageBackupRunner (mBackupRunner) for the current package. 4544 * - Wait until preflight is complete. (mBackupRunner.getPreflightResultBlocking()) 4545 * - If preflight data size is within limit, start reading data from agent pipe and writing 4546 * to transport pipe. While there is data to send, call transport.sendBackupData(int) to 4547 * tell the transport how many bytes to expect on its pipe. 4548 * - After sending all data, call transport.finishBackup() if things went well. And 4549 * transport.cancelFullBackup() otherwise. 4550 * 4551 * Interactions with mCurrentOperations: 4552 * - An entry for this object is added to mCurrentOperations for the entire lifetime of this 4553 * object. Used to cancel the operation. 4554 * - SinglePackageBackupRunner and SinglePackageBackupPreflight will put ephemeral entries 4555 * to get timeouts or operation complete callbacks. 4556 * 4557 * Handling cancels: 4558 * - The contract we provide is that the task won't interact with the transport after 4559 * handleCancel() is done executing. 4560 * - This task blocks at 3 points: 1. Preflight result check 2. Reading on agent side pipe 4561 * and 3. Get backup result from mBackupRunner. 4562 * - Bubbling up handleCancel to mBackupRunner handles all 3: 1. Calls handleCancel on the 4563 * preflight operation which counts down on the preflight latch. 2. Tears down the agent, 4564 * so read() returns -1. 3. Notifies mCurrentOpLock which unblocks 4565 * mBackupRunner.getBackupResultBlocking(). 4566 */ 4567 class PerformFullTransportBackupTask extends FullBackupTask implements BackupRestoreTask { 4568 static final String TAG = "PFTBT"; 4569 4570 private final Object mCancelLock = new Object(); 4571 4572 ArrayList<PackageInfo> mPackages; 4573 PackageInfo mCurrentPackage; 4574 boolean mUpdateSchedule; 4575 CountDownLatch mLatch; 4576 FullBackupJob mJob; // if a scheduled job needs to be finished afterwards 4577 IBackupObserver mBackupObserver; 4578 IBackupManagerMonitor mMonitor; 4579 boolean mUserInitiated; 4580 private volatile IBackupTransport mTransport; 4581 SinglePackageBackupRunner mBackupRunner; 4582 private final int mBackupRunnerOpToken; 4583 4584 // This is true when a backup operation for some package is in progress. 4585 private volatile boolean mIsDoingBackup; 4586 private volatile boolean mCancelAll; 4587 private final int mCurrentOpToken; 4588 4589 PerformFullTransportBackupTask(IFullBackupRestoreObserver observer, 4590 String[] whichPackages, boolean updateSchedule, 4591 FullBackupJob runningJob, CountDownLatch latch, IBackupObserver backupObserver, 4592 IBackupManagerMonitor monitor, boolean userInitiated) { 4593 super(observer); 4594 mUpdateSchedule = updateSchedule; 4595 mLatch = latch; 4596 mJob = runningJob; 4597 mPackages = new ArrayList<PackageInfo>(whichPackages.length); 4598 mBackupObserver = backupObserver; 4599 mMonitor = monitor; 4600 mUserInitiated = userInitiated; 4601 mCurrentOpToken = generateToken(); 4602 mBackupRunnerOpToken = generateToken(); 4603 4604 if (isBackupOperationInProgress()) { 4605 if (DEBUG) { 4606 Slog.d(TAG, "Skipping full backup. A backup is already in progress."); 4607 } 4608 mCancelAll = true; 4609 return; 4610 } 4611 4612 registerTask(); 4613 4614 for (String pkg : whichPackages) { 4615 try { 4616 PackageInfo info = mPackageManager.getPackageInfo(pkg, 4617 PackageManager.GET_SIGNATURES); 4618 mCurrentPackage = info; 4619 if (!appIsEligibleForBackup(info.applicationInfo)) { 4620 // Cull any packages that have indicated that backups are not permitted, 4621 // that run as system-domain uids but do not define their own backup agents, 4622 // as well as any explicit mention of the 'special' shared-storage agent 4623 // package (we handle that one at the end). 4624 if (MORE_DEBUG) { 4625 Slog.d(TAG, "Ignoring ineligible package " + pkg); 4626 } 4627 mMonitor = monitorEvent(mMonitor, 4628 BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_INELIGIBLE, 4629 mCurrentPackage, 4630 BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, 4631 null); 4632 sendBackupOnPackageResult(mBackupObserver, pkg, 4633 BackupManager.ERROR_BACKUP_NOT_ALLOWED); 4634 continue; 4635 } else if (!appGetsFullBackup(info)) { 4636 // Cull any packages that are found in the queue but now aren't supposed 4637 // to get full-data backup operations. 4638 if (MORE_DEBUG) { 4639 Slog.d(TAG, "Ignoring full-data backup of key/value participant " 4640 + pkg); 4641 } 4642 mMonitor = monitorEvent(mMonitor, 4643 BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_KEY_VALUE_PARTICIPANT, 4644 mCurrentPackage, 4645 BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, 4646 null); 4647 sendBackupOnPackageResult(mBackupObserver, pkg, 4648 BackupManager.ERROR_BACKUP_NOT_ALLOWED); 4649 continue; 4650 } else if (appIsStopped(info.applicationInfo)) { 4651 // Cull any packages in the 'stopped' state: they've either just been 4652 // installed or have explicitly been force-stopped by the user. In both 4653 // cases we do not want to launch them for backup. 4654 if (MORE_DEBUG) { 4655 Slog.d(TAG, "Ignoring stopped package " + pkg); 4656 } 4657 mMonitor = monitorEvent(mMonitor, 4658 BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_STOPPED, 4659 mCurrentPackage, 4660 BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, 4661 null); 4662 sendBackupOnPackageResult(mBackupObserver, pkg, 4663 BackupManager.ERROR_BACKUP_NOT_ALLOWED); 4664 continue; 4665 } 4666 mPackages.add(info); 4667 } catch (NameNotFoundException e) { 4668 Slog.i(TAG, "Requested package " + pkg + " not found; ignoring"); 4669 mMonitor = monitorEvent(mMonitor, 4670 BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_NOT_FOUND, 4671 mCurrentPackage, 4672 BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, 4673 null); 4674 } 4675 } 4676 } 4677 4678 private void registerTask() { 4679 synchronized (mCurrentOpLock) { 4680 Slog.d(TAG, "backupmanager pftbt token=" + Integer.toHexString(mCurrentOpToken)); 4681 mCurrentOperations.put(mCurrentOpToken, new Operation(OP_PENDING, this, 4682 OP_TYPE_BACKUP)); 4683 } 4684 } 4685 4686 private void unregisterTask() { 4687 removeOperation(mCurrentOpToken); 4688 } 4689 4690 @Override 4691 public void execute() { 4692 // Nothing to do. 4693 } 4694 4695 @Override 4696 public void handleCancel(boolean cancelAll) { 4697 synchronized (mCancelLock) { 4698 // We only support 'cancelAll = true' case for this task. Cancelling of a single package 4699 4700 // due to timeout is handled by SinglePackageBackupRunner and SinglePackageBackupPreflight. 4701 4702 if (!cancelAll) { 4703 Slog.wtf(TAG, "Expected cancelAll to be true."); 4704 } 4705 4706 if (mCancelAll) { 4707 Slog.d(TAG, "Ignoring duplicate cancel call."); 4708 return; 4709 } 4710 4711 mCancelAll = true; 4712 if (mIsDoingBackup) { 4713 BackupManagerService.this.handleCancel(mBackupRunnerOpToken, cancelAll); 4714 try { 4715 mTransport.cancelFullBackup(); 4716 } catch (RemoteException e) { 4717 Slog.w(TAG, "Error calling cancelFullBackup() on transport: " + e); 4718 // Can't do much. 4719 } 4720 } 4721 } 4722 } 4723 4724 @Override 4725 public void operationComplete(long result) { 4726 // Nothing to do. 4727 } 4728 4729 @Override 4730 public void run() { 4731 4732 // data from the app, passed to us for bridging to the transport 4733 ParcelFileDescriptor[] enginePipes = null; 4734 4735 // Pipe through which we write data to the transport 4736 ParcelFileDescriptor[] transportPipes = null; 4737 4738 long backoff = 0; 4739 int backupRunStatus = BackupManager.SUCCESS; 4740 4741 try { 4742 if (!mEnabled || !mProvisioned) { 4743 // Backups are globally disabled, so don't proceed. 4744 if (DEBUG) { 4745 Slog.i(TAG, "full backup requested but enabled=" + mEnabled 4746 + " provisioned=" + mProvisioned + "; ignoring"); 4747 } 4748 int monitoringEvent; 4749 if (!mEnabled) { 4750 monitoringEvent = BackupManagerMonitor.LOG_EVENT_ID_BACKUP_DISABLED; 4751 } else { 4752 monitoringEvent = BackupManagerMonitor.LOG_EVENT_ID_DEVICE_NOT_PROVISIONED; 4753 } 4754 mMonitor = monitorEvent(mMonitor, monitoringEvent, null, 4755 BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, null); 4756 mUpdateSchedule = false; 4757 backupRunStatus = BackupManager.ERROR_BACKUP_NOT_ALLOWED; 4758 return; 4759 } 4760 4761 mTransport = mTransportManager.getCurrentTransportBinder(); 4762 if (mTransport == null) { 4763 Slog.w(TAG, "Transport not present; full data backup not performed"); 4764 backupRunStatus = BackupManager.ERROR_TRANSPORT_ABORTED; 4765 mMonitor = monitorEvent(mMonitor, 4766 BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_TRANSPORT_NOT_PRESENT, 4767 mCurrentPackage, BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT, 4768 null); 4769 return; 4770 } 4771 4772 // Set up to send data to the transport 4773 final int N = mPackages.size(); 4774 final byte[] buffer = new byte[8192]; 4775 for (int i = 0; i < N; i++) { 4776 PackageInfo currentPackage = mPackages.get(i); 4777 String packageName = currentPackage.packageName; 4778 if (DEBUG) { 4779 Slog.i(TAG, "Initiating full-data transport backup of " + packageName 4780 + " token: " + mCurrentOpToken); 4781 } 4782 EventLog.writeEvent(EventLogTags.FULL_BACKUP_PACKAGE, packageName); 4783 4784 transportPipes = ParcelFileDescriptor.createPipe(); 4785 4786 // Tell the transport the data's coming 4787 int flags = mUserInitiated ? BackupTransport.FLAG_USER_INITIATED : 0; 4788 int backupPackageStatus; 4789 long quota = Long.MAX_VALUE; 4790 synchronized (mCancelLock) { 4791 if (mCancelAll) { 4792 break; 4793 } 4794 backupPackageStatus = mTransport.performFullBackup(currentPackage, 4795 transportPipes[0], flags); 4796 4797 if (backupPackageStatus == BackupTransport.TRANSPORT_OK) { 4798 quota = mTransport.getBackupQuota(currentPackage.packageName, 4799 true /* isFullBackup */); 4800 // Now set up the backup engine / data source end of things 4801 enginePipes = ParcelFileDescriptor.createPipe(); 4802 mBackupRunner = 4803 new SinglePackageBackupRunner(enginePipes[1], currentPackage, 4804 mTransport, quota, mBackupRunnerOpToken); 4805 // The runner dup'd the pipe half, so we close it here 4806 enginePipes[1].close(); 4807 enginePipes[1] = null; 4808 4809 mIsDoingBackup = true; 4810 } 4811 } 4812 if (backupPackageStatus == BackupTransport.TRANSPORT_OK) { 4813 4814 // The transport has its own copy of the read end of the pipe, 4815 // so close ours now 4816 transportPipes[0].close(); 4817 transportPipes[0] = null; 4818 4819 // Spin off the runner to fetch the app's data and pipe it 4820 // into the engine pipes 4821 (new Thread(mBackupRunner, "package-backup-bridge")).start(); 4822 4823 // Read data off the engine pipe and pass it to the transport 4824 // pipe until we hit EOD on the input stream. We do not take 4825 // close() responsibility for these FDs into these stream wrappers. 4826 FileInputStream in = new FileInputStream( 4827 enginePipes[0].getFileDescriptor()); 4828 FileOutputStream out = new FileOutputStream( 4829 transportPipes[1].getFileDescriptor()); 4830 long totalRead = 0; 4831 final long preflightResult = mBackupRunner.getPreflightResultBlocking(); 4832 // Preflight result is negative if some error happened on preflight. 4833 if (preflightResult < 0) { 4834 if (MORE_DEBUG) { 4835 Slog.d(TAG, "Backup error after preflight of package " 4836 + packageName + ": " + preflightResult 4837 + ", not running backup."); 4838 } 4839 mMonitor = monitorEvent(mMonitor, 4840 BackupManagerMonitor.LOG_EVENT_ID_ERROR_PREFLIGHT, 4841 mCurrentPackage, 4842 BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, 4843 putMonitoringExtra(null, 4844 BackupManagerMonitor.EXTRA_LOG_PREFLIGHT_ERROR, 4845 preflightResult)); 4846 backupPackageStatus = (int) preflightResult; 4847 } else { 4848 int nRead = 0; 4849 do { 4850 nRead = in.read(buffer); 4851 if (MORE_DEBUG) { 4852 Slog.v(TAG, "in.read(buffer) from app: " + nRead); 4853 } 4854 if (nRead > 0) { 4855 out.write(buffer, 0, nRead); 4856 synchronized (mCancelLock) { 4857 if (!mCancelAll) { 4858 backupPackageStatus = mTransport.sendBackupData(nRead); 4859 } 4860 } 4861 totalRead += nRead; 4862 if (mBackupObserver != null && preflightResult > 0) { 4863 sendBackupOnUpdate(mBackupObserver, packageName, 4864 new BackupProgress(preflightResult, totalRead)); 4865 } 4866 } 4867 } while (nRead > 0 4868 && backupPackageStatus == BackupTransport.TRANSPORT_OK); 4869 // Despite preflight succeeded, package still can hit quota on flight. 4870 if (backupPackageStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) { 4871 Slog.w(TAG, "Package hit quota limit in-flight " + packageName 4872 + ": " + totalRead + " of " + quota); 4873 mMonitor = monitorEvent(mMonitor, 4874 BackupManagerMonitor.LOG_EVENT_ID_QUOTA_HIT_PREFLIGHT, 4875 mCurrentPackage, 4876 BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT, 4877 null); 4878 mBackupRunner.sendQuotaExceeded(totalRead, quota); 4879 } 4880 } 4881 4882 final int backupRunnerResult = mBackupRunner.getBackupResultBlocking(); 4883 4884 synchronized (mCancelLock) { 4885 mIsDoingBackup = false; 4886 // If mCancelCurrent is true, we have already called cancelFullBackup(). 4887 if (!mCancelAll) { 4888 if (backupRunnerResult == BackupTransport.TRANSPORT_OK) { 4889 // If we were otherwise in a good state, now interpret the final 4890 // result based on what finishBackup() returns. If we're in a 4891 // failure case already, preserve that result and ignore whatever 4892 // finishBackup() reports. 4893 final int finishResult = mTransport.finishBackup(); 4894 if (backupPackageStatus == BackupTransport.TRANSPORT_OK) { 4895 backupPackageStatus = finishResult; 4896 } 4897 } else { 4898 mTransport.cancelFullBackup(); 4899 } 4900 } 4901 } 4902 4903 // A transport-originated error here means that we've hit an error that the 4904 // runner doesn't know about, so it's still moving data but we're pulling the 4905 // rug out from under it. Don't ask for its result: we already know better 4906 // and we'll hang if we block waiting for it, since it relies on us to 4907 // read back the data it's writing into the engine. Just proceed with 4908 // a graceful failure. The runner/engine mechanism will tear itself 4909 // down cleanly when we close the pipes from this end. Transport-level 4910 // errors take precedence over agent/app-specific errors for purposes of 4911 // determining our course of action. 4912 if (backupPackageStatus == BackupTransport.TRANSPORT_OK) { 4913 // We still could fail in backup runner thread. 4914 if (backupRunnerResult != BackupTransport.TRANSPORT_OK) { 4915 // If there was an error in runner thread and 4916 // not TRANSPORT_ERROR here, overwrite it. 4917 backupPackageStatus = backupRunnerResult; 4918 } 4919 } else { 4920 if (MORE_DEBUG) { 4921 Slog.i(TAG, "Transport-level failure; cancelling agent work"); 4922 } 4923 } 4924 4925 if (MORE_DEBUG) { 4926 Slog.i(TAG, "Done delivering backup data: result=" 4927 + backupPackageStatus); 4928 } 4929 4930 if (backupPackageStatus != BackupTransport.TRANSPORT_OK) { 4931 Slog.e(TAG, "Error " + backupPackageStatus + " backing up " 4932 + packageName); 4933 } 4934 4935 // Also ask the transport how long it wants us to wait before 4936 // moving on to the next package, if any. 4937 backoff = mTransport.requestFullBackupTime(); 4938 if (DEBUG_SCHEDULING) { 4939 Slog.i(TAG, "Transport suggested backoff=" + backoff); 4940 } 4941 4942 } 4943 4944 // Roll this package to the end of the backup queue if we're 4945 // in a queue-driven mode (regardless of success/failure) 4946 if (mUpdateSchedule) { 4947 enqueueFullBackup(packageName, System.currentTimeMillis()); 4948 } 4949 4950 if (backupPackageStatus == BackupTransport.TRANSPORT_PACKAGE_REJECTED) { 4951 sendBackupOnPackageResult(mBackupObserver, packageName, 4952 BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED); 4953 if (DEBUG) { 4954 Slog.i(TAG, "Transport rejected backup of " + packageName 4955 + ", skipping"); 4956 } 4957 EventLog.writeEvent(EventLogTags.FULL_BACKUP_AGENT_FAILURE, packageName, 4958 "transport rejected"); 4959 // Do nothing, clean up, and continue looping. 4960 } else if (backupPackageStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) { 4961 sendBackupOnPackageResult(mBackupObserver, packageName, 4962 BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED); 4963 if (DEBUG) { 4964 Slog.i(TAG, "Transport quota exceeded for package: " + packageName); 4965 EventLog.writeEvent(EventLogTags.FULL_BACKUP_QUOTA_EXCEEDED, 4966 packageName); 4967 } 4968 // Do nothing, clean up, and continue looping. 4969 } else if (backupPackageStatus == BackupTransport.AGENT_ERROR) { 4970 sendBackupOnPackageResult(mBackupObserver, packageName, 4971 BackupManager.ERROR_AGENT_FAILURE); 4972 Slog.w(TAG, "Application failure for package: " + packageName); 4973 EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName); 4974 tearDownAgentAndKill(currentPackage.applicationInfo); 4975 // Do nothing, clean up, and continue looping. 4976 } else if (backupPackageStatus == BackupManager.ERROR_BACKUP_CANCELLED) { 4977 sendBackupOnPackageResult(mBackupObserver, packageName, 4978 BackupManager.ERROR_BACKUP_CANCELLED); 4979 Slog.w(TAG, "Backup cancelled. package=" + packageName + 4980 ", cancelAll=" + mCancelAll); 4981 EventLog.writeEvent(EventLogTags.FULL_BACKUP_CANCELLED, packageName); 4982 tearDownAgentAndKill(currentPackage.applicationInfo); 4983 // Do nothing, clean up, and continue looping. 4984 } else if (backupPackageStatus != BackupTransport.TRANSPORT_OK) { 4985 sendBackupOnPackageResult(mBackupObserver, packageName, 4986 BackupManager.ERROR_TRANSPORT_ABORTED); 4987 Slog.w(TAG, "Transport failed; aborting backup: " + backupPackageStatus); 4988 EventLog.writeEvent(EventLogTags.FULL_BACKUP_TRANSPORT_FAILURE); 4989 // Abort entire backup pass. 4990 backupRunStatus = BackupManager.ERROR_TRANSPORT_ABORTED; 4991 return; 4992 } else { 4993 // Success! 4994 sendBackupOnPackageResult(mBackupObserver, packageName, 4995 BackupManager.SUCCESS); 4996 EventLog.writeEvent(EventLogTags.FULL_BACKUP_SUCCESS, packageName); 4997 logBackupComplete(packageName); 4998 } 4999 cleanUpPipes(transportPipes); 5000 cleanUpPipes(enginePipes); 5001 if (currentPackage.applicationInfo != null) { 5002 Slog.i(TAG, "Unbinding agent in " + packageName); 5003 addBackupTrace("unbinding " + packageName); 5004 try { 5005 mActivityManager.unbindBackupAgent(currentPackage.applicationInfo); 5006 } catch (RemoteException e) { /* can't happen; activity manager is local */ } 5007 } 5008 } 5009 } catch (Exception e) { 5010 backupRunStatus = BackupManager.ERROR_TRANSPORT_ABORTED; 5011 Slog.w(TAG, "Exception trying full transport backup", e); 5012 mMonitor = monitorEvent(mMonitor, 5013 BackupManagerMonitor.LOG_EVENT_ID_EXCEPTION_FULL_BACKUP, 5014 mCurrentPackage, 5015 BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, 5016 putMonitoringExtra(null, 5017 BackupManagerMonitor.EXTRA_LOG_EXCEPTION_FULL_BACKUP, 5018 Log.getStackTraceString(e))); 5019 5020 } finally { 5021 5022 if (mCancelAll) { 5023 backupRunStatus = BackupManager.ERROR_BACKUP_CANCELLED; 5024 } 5025 5026 if (DEBUG) { 5027 Slog.i(TAG, "Full backup completed with status: " + backupRunStatus); 5028 } 5029 sendBackupFinished(mBackupObserver, backupRunStatus); 5030 5031 cleanUpPipes(transportPipes); 5032 cleanUpPipes(enginePipes); 5033 5034 unregisterTask(); 5035 5036 if (mJob != null) { 5037 mJob.finishBackupPass(); 5038 } 5039 5040 synchronized (mQueueLock) { 5041 mRunningFullBackupTask = null; 5042 } 5043 5044 mLatch.countDown(); 5045 5046 // Now that we're actually done with schedule-driven work, reschedule 5047 // the next pass based on the new queue state. 5048 if (mUpdateSchedule) { 5049 scheduleNextFullBackupJob(backoff); 5050 } 5051 5052 Slog.i(BackupManagerService.TAG, "Full data backup pass finished."); 5053 mWakelock.release(); 5054 } 5055 } 5056 5057 void cleanUpPipes(ParcelFileDescriptor[] pipes) { 5058 if (pipes != null) { 5059 if (pipes[0] != null) { 5060 ParcelFileDescriptor fd = pipes[0]; 5061 pipes[0] = null; 5062 try { 5063 fd.close(); 5064 } catch (IOException e) { 5065 Slog.w(TAG, "Unable to close pipe!"); 5066 } 5067 } 5068 if (pipes[1] != null) { 5069 ParcelFileDescriptor fd = pipes[1]; 5070 pipes[1] = null; 5071 try { 5072 fd.close(); 5073 } catch (IOException e) { 5074 Slog.w(TAG, "Unable to close pipe!"); 5075 } 5076 } 5077 } 5078 } 5079 5080 // Run the backup and pipe it back to the given socket -- expects to run on 5081 // a standalone thread. The runner owns this half of the pipe, and closes 5082 // it to indicate EOD to the other end. 5083 class SinglePackageBackupPreflight implements BackupRestoreTask, FullBackupPreflight { 5084 final AtomicLong mResult = new AtomicLong(BackupTransport.AGENT_ERROR); 5085 final CountDownLatch mLatch = new CountDownLatch(1); 5086 final IBackupTransport mTransport; 5087 final long mQuota; 5088 private final int mCurrentOpToken; 5089 5090 SinglePackageBackupPreflight(IBackupTransport transport, long quota, int currentOpToken) { 5091 mTransport = transport; 5092 mQuota = quota; 5093 mCurrentOpToken = currentOpToken; 5094 } 5095 5096 @Override 5097 public int preflightFullBackup(PackageInfo pkg, IBackupAgent agent) { 5098 int result; 5099 try { 5100 prepareOperationTimeout(mCurrentOpToken, TIMEOUT_FULL_BACKUP_INTERVAL, 5101 this, OP_TYPE_BACKUP_WAIT); 5102 addBackupTrace("preflighting"); 5103 if (MORE_DEBUG) { 5104 Slog.d(TAG, "Preflighting full payload of " + pkg.packageName); 5105 } 5106 agent.doMeasureFullBackup(mQuota, mCurrentOpToken, mBackupManagerBinder); 5107 5108 // Now wait to get our result back. If this backstop timeout is reached without 5109 // the latch being thrown, flow will continue as though a result or "normal" 5110 // timeout had been produced. In case of a real backstop timeout, mResult 5111 // will still contain the value it was constructed with, AGENT_ERROR, which 5112 // intentionaly falls into the "just report failure" code. 5113 mLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS); 5114 5115 long totalSize = mResult.get(); 5116 // If preflight timed out, mResult will contain error code as int. 5117 if (totalSize < 0) { 5118 return (int) totalSize; 5119 } 5120 if (MORE_DEBUG) { 5121 Slog.v(TAG, "Got preflight response; size=" + totalSize); 5122 } 5123 5124 result = mTransport.checkFullBackupSize(totalSize); 5125 if (result == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) { 5126 if (MORE_DEBUG) { 5127 Slog.d(TAG, "Package hit quota limit on preflight " + 5128 pkg.packageName + ": " + totalSize + " of " + mQuota); 5129 } 5130 agent.doQuotaExceeded(totalSize, mQuota); 5131 } 5132 } catch (Exception e) { 5133 Slog.w(TAG, "Exception preflighting " + pkg.packageName + ": " + e.getMessage()); 5134 result = BackupTransport.AGENT_ERROR; 5135 } 5136 return result; 5137 } 5138 5139 @Override 5140 public void execute() { 5141 // Unused. 5142 } 5143 5144 @Override 5145 public void operationComplete(long result) { 5146 // got the callback, and our preflightFullBackup() method is waiting for the result 5147 if (MORE_DEBUG) { 5148 Slog.i(TAG, "Preflight op complete, result=" + result); 5149 } 5150 mResult.set(result); 5151 mLatch.countDown(); 5152 removeOperation(mCurrentOpToken); 5153 } 5154 5155 @Override 5156 public void handleCancel(boolean cancelAll) { 5157 if (MORE_DEBUG) { 5158 Slog.i(TAG, "Preflight cancelled; failing"); 5159 } 5160 mResult.set(BackupTransport.AGENT_ERROR); 5161 mLatch.countDown(); 5162 removeOperation(mCurrentOpToken); 5163 } 5164 5165 @Override 5166 public long getExpectedSizeOrErrorCode() { 5167 try { 5168 mLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS); 5169 return mResult.get(); 5170 } catch (InterruptedException e) { 5171 return BackupTransport.NO_MORE_DATA; 5172 } 5173 } 5174 } 5175 5176 class SinglePackageBackupRunner implements Runnable, BackupRestoreTask { 5177 final ParcelFileDescriptor mOutput; 5178 final PackageInfo mTarget; 5179 final SinglePackageBackupPreflight mPreflight; 5180 final CountDownLatch mPreflightLatch; 5181 final CountDownLatch mBackupLatch; 5182 private final int mCurrentOpToken; 5183 private final int mEphemeralToken; 5184 private FullBackupEngine mEngine; 5185 private volatile int mPreflightResult; 5186 private volatile int mBackupResult; 5187 private final long mQuota; 5188 private volatile boolean mIsCancelled; 5189 5190 SinglePackageBackupRunner(ParcelFileDescriptor output, PackageInfo target, 5191 IBackupTransport transport, long quota, int currentOpToken) throws IOException { 5192 mOutput = ParcelFileDescriptor.dup(output.getFileDescriptor()); 5193 mTarget = target; 5194 mCurrentOpToken = currentOpToken; 5195 mEphemeralToken = generateToken(); 5196 mPreflight = new SinglePackageBackupPreflight(transport, quota, mEphemeralToken); 5197 mPreflightLatch = new CountDownLatch(1); 5198 mBackupLatch = new CountDownLatch(1); 5199 mPreflightResult = BackupTransport.AGENT_ERROR; 5200 mBackupResult = BackupTransport.AGENT_ERROR; 5201 mQuota = quota; 5202 registerTask(); 5203 } 5204 5205 void registerTask() { 5206 synchronized (mCurrentOpLock) { 5207 mCurrentOperations.put(mCurrentOpToken, new Operation(OP_PENDING, this, 5208 OP_TYPE_BACKUP_WAIT)); 5209 } 5210 } 5211 5212 void unregisterTask() { 5213 synchronized (mCurrentOpLock) { 5214 mCurrentOperations.remove(mCurrentOpToken); 5215 } 5216 } 5217 5218 @Override 5219 public void run() { 5220 FileOutputStream out = new FileOutputStream(mOutput.getFileDescriptor()); 5221 mEngine = new FullBackupEngine(out, mPreflight, mTarget, false, this, mQuota, mCurrentOpToken); 5222 try { 5223 try { 5224 if (!mIsCancelled) { 5225 mPreflightResult = mEngine.preflightCheck(); 5226 } 5227 } finally { 5228 mPreflightLatch.countDown(); 5229 } 5230 // If there is no error on preflight, continue backup. 5231 if (mPreflightResult == BackupTransport.TRANSPORT_OK) { 5232 if (!mIsCancelled) { 5233 mBackupResult = mEngine.backupOnePackage(); 5234 } 5235 } 5236 } catch (Exception e) { 5237 Slog.e(TAG, "Exception during full package backup of " + mTarget.packageName); 5238 } finally { 5239 unregisterTask(); 5240 mBackupLatch.countDown(); 5241 try { 5242 mOutput.close(); 5243 } catch (IOException e) { 5244 Slog.w(TAG, "Error closing transport pipe in runner"); 5245 } 5246 } 5247 } 5248 5249 public void sendQuotaExceeded(final long backupDataBytes, final long quotaBytes) { 5250 mEngine.sendQuotaExceeded(backupDataBytes, quotaBytes); 5251 } 5252 5253 // If preflight succeeded, returns positive number - preflight size, 5254 // otherwise return negative error code. 5255 long getPreflightResultBlocking() { 5256 try { 5257 mPreflightLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS); 5258 if (mIsCancelled) { 5259 return BackupManager.ERROR_BACKUP_CANCELLED; 5260 } 5261 if (mPreflightResult == BackupTransport.TRANSPORT_OK) { 5262 return mPreflight.getExpectedSizeOrErrorCode(); 5263 } else { 5264 return mPreflightResult; 5265 } 5266 } catch (InterruptedException e) { 5267 return BackupTransport.AGENT_ERROR; 5268 } 5269 } 5270 5271 int getBackupResultBlocking() { 5272 try { 5273 mBackupLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS); 5274 if (mIsCancelled) { 5275 return BackupManager.ERROR_BACKUP_CANCELLED; 5276 } 5277 return mBackupResult; 5278 } catch (InterruptedException e) { 5279 return BackupTransport.AGENT_ERROR; 5280 } 5281 } 5282 5283 5284 // BackupRestoreTask interface: specifically, timeout detection 5285 5286 @Override 5287 public void execute() { /* intentionally empty */ } 5288 5289 @Override 5290 public void operationComplete(long result) { /* intentionally empty */ } 5291 5292 @Override 5293 public void handleCancel(boolean cancelAll) { 5294 if (DEBUG) { 5295 Slog.w(TAG, "Full backup cancel of " + mTarget.packageName); 5296 } 5297 5298 mMonitor = monitorEvent(mMonitor, 5299 BackupManagerMonitor.LOG_EVENT_ID_FULL_BACKUP_CANCEL, 5300 mCurrentPackage, BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT, null); 5301 mIsCancelled = true; 5302 // Cancel tasks spun off by this task. 5303 BackupManagerService.this.handleCancel(mEphemeralToken, cancelAll); 5304 tearDownAgentAndKill(mTarget.applicationInfo); 5305 // Free up everyone waiting on this task and its children. 5306 mPreflightLatch.countDown(); 5307 mBackupLatch.countDown(); 5308 // We are done with this operation. 5309 removeOperation(mCurrentOpToken); 5310 } 5311 } 5312 } 5313 5314 // ----- Full-data backup scheduling ----- 5315 5316 /** 5317 * Schedule a job to tell us when it's a good time to run a full backup 5318 */ 5319 void scheduleNextFullBackupJob(long transportMinLatency) { 5320 synchronized (mQueueLock) { 5321 if (mFullBackupQueue.size() > 0) { 5322 // schedule the next job at the point in the future when the least-recently 5323 // backed up app comes due for backup again; or immediately if it's already 5324 // due. 5325 final long upcomingLastBackup = mFullBackupQueue.get(0).lastBackup; 5326 final long timeSinceLast = System.currentTimeMillis() - upcomingLastBackup; 5327 final long appLatency = (timeSinceLast < MIN_FULL_BACKUP_INTERVAL) 5328 ? (MIN_FULL_BACKUP_INTERVAL - timeSinceLast) : 0; 5329 final long latency = Math.max(transportMinLatency, appLatency); 5330 Runnable r = new Runnable() { 5331 @Override public void run() { 5332 FullBackupJob.schedule(mContext, latency); 5333 } 5334 }; 5335 mBackupHandler.postDelayed(r, 2500); 5336 } else { 5337 if (DEBUG_SCHEDULING) { 5338 Slog.i(TAG, "Full backup queue empty; not scheduling"); 5339 } 5340 } 5341 } 5342 } 5343 5344 /** 5345 * Remove a package from the full-data queue. 5346 */ 5347 void dequeueFullBackupLocked(String packageName) { 5348 final int N = mFullBackupQueue.size(); 5349 for (int i = N-1; i >= 0; i--) { 5350 final FullBackupEntry e = mFullBackupQueue.get(i); 5351 if (packageName.equals(e.packageName)) { 5352 mFullBackupQueue.remove(i); 5353 } 5354 } 5355 } 5356 5357 /** 5358 * Enqueue full backup for the given app, with a note about when it last ran. 5359 */ 5360 void enqueueFullBackup(String packageName, long lastBackedUp) { 5361 FullBackupEntry newEntry = new FullBackupEntry(packageName, lastBackedUp); 5362 synchronized (mQueueLock) { 5363 // First, sanity check that we aren't adding a duplicate. Slow but 5364 // straightforward; we'll have at most on the order of a few hundred 5365 // items in this list. 5366 dequeueFullBackupLocked(packageName); 5367 5368 // This is also slow but easy for modest numbers of apps: work backwards 5369 // from the end of the queue until we find an item whose last backup 5370 // time was before this one, then insert this new entry after it. If we're 5371 // adding something new we don't bother scanning, and just prepend. 5372 int which = -1; 5373 if (lastBackedUp > 0) { 5374 for (which = mFullBackupQueue.size() - 1; which >= 0; which--) { 5375 final FullBackupEntry entry = mFullBackupQueue.get(which); 5376 if (entry.lastBackup <= lastBackedUp) { 5377 mFullBackupQueue.add(which + 1, newEntry); 5378 break; 5379 } 5380 } 5381 } 5382 if (which < 0) { 5383 // this one is earlier than any existing one, so prepend 5384 mFullBackupQueue.add(0, newEntry); 5385 } 5386 } 5387 writeFullBackupScheduleAsync(); 5388 } 5389 5390 private boolean fullBackupAllowable(IBackupTransport transport) { 5391 if (transport == null) { 5392 Slog.w(TAG, "Transport not present; full data backup not performed"); 5393 return false; 5394 } 5395 5396 // Don't proceed unless we have already established package metadata 5397 // for the current dataset via a key/value backup pass. 5398 try { 5399 File stateDir = new File(mBaseStateDir, transport.transportDirName()); 5400 File pmState = new File(stateDir, PACKAGE_MANAGER_SENTINEL); 5401 if (pmState.length() <= 0) { 5402 if (DEBUG) { 5403 Slog.i(TAG, "Full backup requested but dataset not yet initialized"); 5404 } 5405 return false; 5406 } 5407 } catch (Exception e) { 5408 Slog.w(TAG, "Unable to get transport name: " + e.getMessage()); 5409 return false; 5410 } 5411 5412 return true; 5413 } 5414 5415 /** 5416 * Conditions are right for a full backup operation, so run one. The model we use is 5417 * to perform one app backup per scheduled job execution, and to reschedule the job 5418 * with zero latency as long as conditions remain right and we still have work to do. 5419 * 5420 * <p>This is the "start a full backup operation" entry point called by the scheduled job. 5421 * 5422 * @return Whether ongoing work will continue. The return value here will be passed 5423 * along as the return value to the scheduled job's onStartJob() callback. 5424 */ 5425 boolean beginFullBackup(FullBackupJob scheduledJob) { 5426 long now = System.currentTimeMillis(); 5427 FullBackupEntry entry = null; 5428 long latency = MIN_FULL_BACKUP_INTERVAL; 5429 5430 if (!mEnabled || !mProvisioned) { 5431 // Backups are globally disabled, so don't proceed. We also don't reschedule 5432 // the job driving automatic backups; that job will be scheduled again when 5433 // the user enables backup. 5434 if (MORE_DEBUG) { 5435 Slog.i(TAG, "beginFullBackup but e=" + mEnabled 5436 + " p=" + mProvisioned + "; ignoring"); 5437 } 5438 return false; 5439 } 5440 5441 // Don't run the backup if we're in battery saver mode, but reschedule 5442 // to try again in the not-so-distant future. 5443 if (mPowerManager.isPowerSaveMode()) { 5444 if (DEBUG) Slog.i(TAG, "Deferring scheduled full backups in battery saver mode"); 5445 FullBackupJob.schedule(mContext, KeyValueBackupJob.BATCH_INTERVAL); 5446 return false; 5447 } 5448 5449 if (DEBUG_SCHEDULING) { 5450 Slog.i(TAG, "Beginning scheduled full backup operation"); 5451 } 5452 5453 // Great; we're able to run full backup jobs now. See if we have any work to do. 5454 synchronized (mQueueLock) { 5455 if (mRunningFullBackupTask != null) { 5456 Slog.e(TAG, "Backup triggered but one already/still running!"); 5457 return false; 5458 } 5459 5460 // At this point we think that we have work to do, but possibly not right now. 5461 // Any exit without actually running backups will also require that we 5462 // reschedule the job. 5463 boolean runBackup = true; 5464 boolean headBusy; 5465 5466 do { 5467 // Recheck each time, because culling due to ineligibility may 5468 // have emptied the queue. 5469 if (mFullBackupQueue.size() == 0) { 5470 // no work to do so just bow out 5471 if (DEBUG) { 5472 Slog.i(TAG, "Backup queue empty; doing nothing"); 5473 } 5474 runBackup = false; 5475 break; 5476 } 5477 5478 headBusy = false; 5479 5480 if (!fullBackupAllowable(mTransportManager.getCurrentTransportBinder())) { 5481 if (MORE_DEBUG) { 5482 Slog.i(TAG, "Preconditions not met; not running full backup"); 5483 } 5484 runBackup = false; 5485 // Typically this means we haven't run a key/value backup yet. Back off 5486 // full-backup operations by the key/value job's run interval so that 5487 // next time we run, we are likely to be able to make progress. 5488 latency = KeyValueBackupJob.BATCH_INTERVAL; 5489 } 5490 5491 if (runBackup) { 5492 entry = mFullBackupQueue.get(0); 5493 long timeSinceRun = now - entry.lastBackup; 5494 runBackup = (timeSinceRun >= MIN_FULL_BACKUP_INTERVAL); 5495 if (!runBackup) { 5496 // It's too early to back up the next thing in the queue, so bow out 5497 if (MORE_DEBUG) { 5498 Slog.i(TAG, "Device ready but too early to back up next app"); 5499 } 5500 // Wait until the next app in the queue falls due for a full data backup 5501 latency = MIN_FULL_BACKUP_INTERVAL - timeSinceRun; 5502 break; // we know we aren't doing work yet, so bail. 5503 } 5504 5505 try { 5506 PackageInfo appInfo = mPackageManager.getPackageInfo(entry.packageName, 0); 5507 if (!appGetsFullBackup(appInfo)) { 5508 // The head app isn't supposed to get full-data backups [any more]; 5509 // so we cull it and force a loop around to consider the new head 5510 // app. 5511 if (MORE_DEBUG) { 5512 Slog.i(TAG, "Culling package " + entry.packageName 5513 + " in full-backup queue but not eligible"); 5514 } 5515 mFullBackupQueue.remove(0); 5516 headBusy = true; // force the while() condition 5517 continue; 5518 } 5519 5520 final int privFlags = appInfo.applicationInfo.privateFlags; 5521 headBusy = (privFlags & PRIVATE_FLAG_BACKUP_IN_FOREGROUND) == 0 5522 && mActivityManager.isAppForeground(appInfo.applicationInfo.uid); 5523 5524 if (headBusy) { 5525 final long nextEligible = System.currentTimeMillis() 5526 + BUSY_BACKOFF_MIN_MILLIS 5527 + mTokenGenerator.nextInt(BUSY_BACKOFF_FUZZ); 5528 if (DEBUG_SCHEDULING) { 5529 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 5530 Slog.i(TAG, "Full backup time but " + entry.packageName 5531 + " is busy; deferring to " 5532 + sdf.format(new Date(nextEligible))); 5533 } 5534 // This relocates the app's entry from the head of the queue to 5535 // its order-appropriate position further down, so upon looping 5536 // a new candidate will be considered at the head. 5537 enqueueFullBackup(entry.packageName, 5538 nextEligible - MIN_FULL_BACKUP_INTERVAL); 5539 } 5540 } catch (NameNotFoundException nnf) { 5541 // So, we think we want to back this up, but it turns out the package 5542 // in question is no longer installed. We want to drop it from the 5543 // queue entirely and move on, but if there's nothing else in the queue 5544 // we should bail entirely. headBusy cannot have been set to true yet. 5545 runBackup = (mFullBackupQueue.size() > 1); 5546 } catch (RemoteException e) { 5547 // Cannot happen; the Activity Manager is in the same process 5548 } 5549 } 5550 } while (headBusy); 5551 5552 if (!runBackup) { 5553 if (DEBUG_SCHEDULING) { 5554 Slog.i(TAG, "Nothing pending full backup; rescheduling +" + latency); 5555 } 5556 final long deferTime = latency; // pin for the closure 5557 mBackupHandler.post(new Runnable() { 5558 @Override public void run() { 5559 FullBackupJob.schedule(mContext, deferTime); 5560 } 5561 }); 5562 return false; 5563 } 5564 5565 // Okay, the top thing is ready for backup now. Do it. 5566 mFullBackupQueue.remove(0); 5567 CountDownLatch latch = new CountDownLatch(1); 5568 String[] pkg = new String[] {entry.packageName}; 5569 mRunningFullBackupTask = new PerformFullTransportBackupTask(null, pkg, true, 5570 scheduledJob, latch, null, null, false /* userInitiated */); 5571 // Acquiring wakelock for PerformFullTransportBackupTask before its start. 5572 mWakelock.acquire(); 5573 (new Thread(mRunningFullBackupTask)).start(); 5574 } 5575 5576 return true; 5577 } 5578 5579 // The job scheduler says our constraints don't hold any more, 5580 // so tear down any ongoing backup task right away. 5581 void endFullBackup() { 5582 synchronized (mQueueLock) { 5583 if (mRunningFullBackupTask != null) { 5584 if (DEBUG_SCHEDULING) { 5585 Slog.i(TAG, "Telling running backup to stop"); 5586 } 5587 mRunningFullBackupTask.handleCancel(true); 5588 } 5589 } 5590 } 5591 5592 // ----- Restore infrastructure ----- 5593 5594 abstract class RestoreEngine { 5595 static final String TAG = "RestoreEngine"; 5596 5597 public static final int SUCCESS = 0; 5598 public static final int TARGET_FAILURE = -2; 5599 public static final int TRANSPORT_FAILURE = -3; 5600 5601 private AtomicBoolean mRunning = new AtomicBoolean(false); 5602 private AtomicInteger mResult = new AtomicInteger(SUCCESS); 5603 5604 public boolean isRunning() { 5605 return mRunning.get(); 5606 } 5607 5608 public void setRunning(boolean stillRunning) { 5609 synchronized (mRunning) { 5610 mRunning.set(stillRunning); 5611 mRunning.notifyAll(); 5612 } 5613 } 5614 5615 public int waitForResult() { 5616 synchronized (mRunning) { 5617 while (isRunning()) { 5618 try { 5619 mRunning.wait(); 5620 } catch (InterruptedException e) {} 5621 } 5622 } 5623 return getResult(); 5624 } 5625 5626 public int getResult() { 5627 return mResult.get(); 5628 } 5629 5630 public void setResult(int result) { 5631 mResult.set(result); 5632 } 5633 5634 // TODO: abstract restore state and APIs 5635 } 5636 5637 // ----- Full restore from a file/socket ----- 5638 5639 // Description of a file in the restore datastream 5640 static class FileMetadata { 5641 String packageName; // name of the owning app 5642 String installerPackageName; // name of the market-type app that installed the owner 5643 int type; // e.g. BackupAgent.TYPE_DIRECTORY 5644 String domain; // e.g. FullBackup.DATABASE_TREE_TOKEN 5645 String path; // subpath within the semantic domain 5646 long mode; // e.g. 0666 (actually int) 5647 long mtime; // last mod time, UTC time_t (actually int) 5648 long size; // bytes of content 5649 5650 @Override 5651 public String toString() { 5652 StringBuilder sb = new StringBuilder(128); 5653 sb.append("FileMetadata{"); 5654 sb.append(packageName); sb.append(','); 5655 sb.append(type); sb.append(','); 5656 sb.append(domain); sb.append(':'); sb.append(path); sb.append(','); 5657 sb.append(size); 5658 sb.append('}'); 5659 return sb.toString(); 5660 } 5661 } 5662 5663 enum RestorePolicy { 5664 IGNORE, 5665 ACCEPT, 5666 ACCEPT_IF_APK 5667 } 5668 5669 // Full restore engine, used by both adb restore and transport-based full restore 5670 class FullRestoreEngine extends RestoreEngine { 5671 // Task in charge of monitoring timeouts 5672 BackupRestoreTask mMonitorTask; 5673 5674 // Dedicated observer, if any 5675 IFullBackupRestoreObserver mObserver; 5676 5677 IBackupManagerMonitor mMonitor; 5678 5679 // Where we're delivering the file data as we go 5680 IBackupAgent mAgent; 5681 5682 // Are we permitted to only deliver a specific package's metadata? 5683 PackageInfo mOnlyPackage; 5684 5685 boolean mAllowApks; 5686 boolean mAllowObbs; 5687 5688 // Which package are we currently handling data for? 5689 String mAgentPackage; 5690 5691 // Info for working with the target app process 5692 ApplicationInfo mTargetApp; 5693 5694 // Machinery for restoring OBBs 5695 FullBackupObbConnection mObbConnection = null; 5696 5697 // possible handling states for a given package in the restore dataset 5698 final HashMap<String, RestorePolicy> mPackagePolicies 5699 = new HashMap<String, RestorePolicy>(); 5700 5701 // installer package names for each encountered app, derived from the manifests 5702 final HashMap<String, String> mPackageInstallers = new HashMap<String, String>(); 5703 5704 // Signatures for a given package found in its manifest file 5705 final HashMap<String, Signature[]> mManifestSignatures 5706 = new HashMap<String, Signature[]>(); 5707 5708 // Packages we've already wiped data on when restoring their first file 5709 final HashSet<String> mClearedPackages = new HashSet<String>(); 5710 5711 // How much data have we moved? 5712 long mBytes; 5713 5714 // Working buffer 5715 byte[] mBuffer; 5716 5717 // Pipes for moving data 5718 ParcelFileDescriptor[] mPipes = null; 5719 5720 // Widget blob to be restored out-of-band 5721 byte[] mWidgetData = null; 5722 5723 private final int mEphemeralOpToken; 5724 5725 // Runner that can be placed in a separate thread to do in-process 5726 // invocations of the full restore API asynchronously. Used by adb restore. 5727 class RestoreFileRunnable implements Runnable { 5728 IBackupAgent mAgent; 5729 FileMetadata mInfo; 5730 ParcelFileDescriptor mSocket; 5731 int mToken; 5732 5733 RestoreFileRunnable(IBackupAgent agent, FileMetadata info, 5734 ParcelFileDescriptor socket, int token) throws IOException { 5735 mAgent = agent; 5736 mInfo = info; 5737 mToken = token; 5738 5739 // This class is used strictly for process-local binder invocations. The 5740 // semantics of ParcelFileDescriptor differ in this case; in particular, we 5741 // do not automatically get a 'dup'ed descriptor that we can can continue 5742 // to use asynchronously from the caller. So, we make sure to dup it ourselves 5743 // before proceeding to do the restore. 5744 mSocket = ParcelFileDescriptor.dup(socket.getFileDescriptor()); 5745 } 5746 5747 @Override 5748 public void run() { 5749 try { 5750 mAgent.doRestoreFile(mSocket, mInfo.size, mInfo.type, 5751 mInfo.domain, mInfo.path, mInfo.mode, mInfo.mtime, 5752 mToken, mBackupManagerBinder); 5753 } catch (RemoteException e) { 5754 // never happens; this is used strictly for local binder calls 5755 } 5756 } 5757 } 5758 5759 public FullRestoreEngine(BackupRestoreTask monitorTask, IFullBackupRestoreObserver observer, 5760 IBackupManagerMonitor monitor, PackageInfo onlyPackage, boolean allowApks, 5761 boolean allowObbs, int ephemeralOpToken) { 5762 mEphemeralOpToken = ephemeralOpToken; 5763 mMonitorTask = monitorTask; 5764 mObserver = observer; 5765 mMonitor = monitor; 5766 mOnlyPackage = onlyPackage; 5767 mAllowApks = allowApks; 5768 mAllowObbs = allowObbs; 5769 mBuffer = new byte[32 * 1024]; 5770 mBytes = 0; 5771 } 5772 5773 public IBackupAgent getAgent() { 5774 return mAgent; 5775 } 5776 5777 public byte[] getWidgetData() { 5778 return mWidgetData; 5779 } 5780 5781 public boolean restoreOneFile(InputStream instream, boolean mustKillAgent) { 5782 if (!isRunning()) { 5783 Slog.w(TAG, "Restore engine used after halting"); 5784 return false; 5785 } 5786 5787 FileMetadata info; 5788 try { 5789 if (MORE_DEBUG) { 5790 Slog.v(TAG, "Reading tar header for restoring file"); 5791 } 5792 info = readTarHeaders(instream); 5793 if (info != null) { 5794 if (MORE_DEBUG) { 5795 dumpFileMetadata(info); 5796 } 5797 5798 final String pkg = info.packageName; 5799 if (!pkg.equals(mAgentPackage)) { 5800 // In the single-package case, it's a semantic error to expect 5801 // one app's data but see a different app's on the wire 5802 if (mOnlyPackage != null) { 5803 if (!pkg.equals(mOnlyPackage.packageName)) { 5804 Slog.w(TAG, "Expected data for " + mOnlyPackage 5805 + " but saw " + pkg); 5806 setResult(RestoreEngine.TRANSPORT_FAILURE); 5807 setRunning(false); 5808 return false; 5809 } 5810 } 5811 5812 // okay, change in package; set up our various 5813 // bookkeeping if we haven't seen it yet 5814 if (!mPackagePolicies.containsKey(pkg)) { 5815 mPackagePolicies.put(pkg, RestorePolicy.IGNORE); 5816 } 5817 5818 // Clean up the previous agent relationship if necessary, 5819 // and let the observer know we're considering a new app. 5820 if (mAgent != null) { 5821 if (DEBUG) Slog.d(TAG, "Saw new package; finalizing old one"); 5822 // Now we're really done 5823 tearDownPipes(); 5824 tearDownAgent(mTargetApp); 5825 mTargetApp = null; 5826 mAgentPackage = null; 5827 } 5828 } 5829 5830 if (info.path.equals(BACKUP_MANIFEST_FILENAME)) { 5831 mPackagePolicies.put(pkg, readAppManifest(info, instream)); 5832 mPackageInstallers.put(pkg, info.installerPackageName); 5833 // We've read only the manifest content itself at this point, 5834 // so consume the footer before looping around to the next 5835 // input file 5836 skipTarPadding(info.size, instream); 5837 sendOnRestorePackage(pkg); 5838 } else if (info.path.equals(BACKUP_METADATA_FILENAME)) { 5839 // Metadata blobs! 5840 readMetadata(info, instream); 5841 skipTarPadding(info.size, instream); 5842 } else { 5843 // Non-manifest, so it's actual file data. Is this a package 5844 // we're ignoring? 5845 boolean okay = true; 5846 RestorePolicy policy = mPackagePolicies.get(pkg); 5847 switch (policy) { 5848 case IGNORE: 5849 okay = false; 5850 break; 5851 5852 case ACCEPT_IF_APK: 5853 // If we're in accept-if-apk state, then the first file we 5854 // see MUST be the apk. 5855 if (info.domain.equals(FullBackup.APK_TREE_TOKEN)) { 5856 if (DEBUG) Slog.d(TAG, "APK file; installing"); 5857 // Try to install the app. 5858 String installerName = mPackageInstallers.get(pkg); 5859 okay = installApk(info, installerName, instream); 5860 // good to go; promote to ACCEPT 5861 mPackagePolicies.put(pkg, (okay) 5862 ? RestorePolicy.ACCEPT 5863 : RestorePolicy.IGNORE); 5864 // At this point we've consumed this file entry 5865 // ourselves, so just strip the tar footer and 5866 // go on to the next file in the input stream 5867 skipTarPadding(info.size, instream); 5868 return true; 5869 } else { 5870 // File data before (or without) the apk. We can't 5871 // handle it coherently in this case so ignore it. 5872 mPackagePolicies.put(pkg, RestorePolicy.IGNORE); 5873 okay = false; 5874 } 5875 break; 5876 5877 case ACCEPT: 5878 if (info.domain.equals(FullBackup.APK_TREE_TOKEN)) { 5879 if (DEBUG) Slog.d(TAG, "apk present but ACCEPT"); 5880 // we can take the data without the apk, so we 5881 // *want* to do so. skip the apk by declaring this 5882 // one file not-okay without changing the restore 5883 // policy for the package. 5884 okay = false; 5885 } 5886 break; 5887 5888 default: 5889 // Something has gone dreadfully wrong when determining 5890 // the restore policy from the manifest. Ignore the 5891 // rest of this package's data. 5892 Slog.e(TAG, "Invalid policy from manifest"); 5893 okay = false; 5894 mPackagePolicies.put(pkg, RestorePolicy.IGNORE); 5895 break; 5896 } 5897 5898 // Is it a *file* we need to drop? 5899 if (!isRestorableFile(info)) { 5900 okay = false; 5901 } 5902 5903 // If the policy is satisfied, go ahead and set up to pipe the 5904 // data to the agent. 5905 if (MORE_DEBUG && okay && mAgent != null) { 5906 Slog.i(TAG, "Reusing existing agent instance"); 5907 } 5908 if (okay && mAgent == null) { 5909 if (MORE_DEBUG) Slog.d(TAG, "Need to launch agent for " + pkg); 5910 5911 try { 5912 mTargetApp = mPackageManager.getApplicationInfo(pkg, 0); 5913 5914 // If we haven't sent any data to this app yet, we probably 5915 // need to clear it first. Check that. 5916 if (!mClearedPackages.contains(pkg)) { 5917 // apps with their own backup agents are 5918 // responsible for coherently managing a full 5919 // restore. 5920 if (mTargetApp.backupAgentName == null) { 5921 if (DEBUG) Slog.d(TAG, "Clearing app data preparatory to full restore"); 5922 clearApplicationDataSynchronous(pkg); 5923 } else { 5924 if (MORE_DEBUG) Slog.d(TAG, "backup agent (" 5925 + mTargetApp.backupAgentName + ") => no clear"); 5926 } 5927 mClearedPackages.add(pkg); 5928 } else { 5929 if (MORE_DEBUG) { 5930 Slog.d(TAG, "We've initialized this app already; no clear required"); 5931 } 5932 } 5933 5934 // All set; now set up the IPC and launch the agent 5935 setUpPipes(); 5936 mAgent = bindToAgentSynchronous(mTargetApp, 5937 ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL); 5938 mAgentPackage = pkg; 5939 } catch (IOException e) { 5940 // fall through to error handling 5941 } catch (NameNotFoundException e) { 5942 // fall through to error handling 5943 } 5944 5945 if (mAgent == null) { 5946 Slog.e(TAG, "Unable to create agent for " + pkg); 5947 okay = false; 5948 tearDownPipes(); 5949 mPackagePolicies.put(pkg, RestorePolicy.IGNORE); 5950 } 5951 } 5952 5953 // Sanity check: make sure we never give data to the wrong app. This 5954 // should never happen but a little paranoia here won't go amiss. 5955 if (okay && !pkg.equals(mAgentPackage)) { 5956 Slog.e(TAG, "Restoring data for " + pkg 5957 + " but agent is for " + mAgentPackage); 5958 okay = false; 5959 } 5960 5961 // At this point we have an agent ready to handle the full 5962 // restore data as well as a pipe for sending data to 5963 // that agent. Tell the agent to start reading from the 5964 // pipe. 5965 if (okay) { 5966 boolean agentSuccess = true; 5967 long toCopy = info.size; 5968 try { 5969 prepareOperationTimeout(mEphemeralOpToken, 5970 TIMEOUT_FULL_BACKUP_INTERVAL, mMonitorTask, 5971 OP_TYPE_RESTORE_WAIT); 5972 5973 if (info.domain.equals(FullBackup.OBB_TREE_TOKEN)) { 5974 if (DEBUG) Slog.d(TAG, "Restoring OBB file for " + pkg 5975 + " : " + info.path); 5976 mObbConnection.restoreObbFile(pkg, mPipes[0], 5977 info.size, info.type, info.path, info.mode, 5978 info.mtime, mEphemeralOpToken, mBackupManagerBinder); 5979 } else { 5980 if (MORE_DEBUG) Slog.d(TAG, "Invoking agent to restore file " 5981 + info.path); 5982 // fire up the app's agent listening on the socket. If 5983 // the agent is running in the system process we can't 5984 // just invoke it asynchronously, so we provide a thread 5985 // for it here. 5986 if (mTargetApp.processName.equals("system")) { 5987 Slog.d(TAG, "system process agent - spinning a thread"); 5988 RestoreFileRunnable runner = new RestoreFileRunnable( 5989 mAgent, info, mPipes[0], mEphemeralOpToken); 5990 new Thread(runner, "restore-sys-runner").start(); 5991 } else { 5992 mAgent.doRestoreFile(mPipes[0], info.size, info.type, 5993 info.domain, info.path, info.mode, info.mtime, 5994 mEphemeralOpToken, mBackupManagerBinder); 5995 } 5996 } 5997 } catch (IOException e) { 5998 // couldn't dup the socket for a process-local restore 5999 Slog.d(TAG, "Couldn't establish restore"); 6000 agentSuccess = false; 6001 okay = false; 6002 } catch (RemoteException e) { 6003 // whoops, remote entity went away. We'll eat the content 6004 // ourselves, then, and not copy it over. 6005 Slog.e(TAG, "Agent crashed during full restore"); 6006 agentSuccess = false; 6007 okay = false; 6008 } 6009 6010 // Copy over the data if the agent is still good 6011 if (okay) { 6012 if (MORE_DEBUG) { 6013 Slog.v(TAG, " copying to restore agent: " 6014 + toCopy + " bytes"); 6015 } 6016 boolean pipeOkay = true; 6017 FileOutputStream pipe = new FileOutputStream( 6018 mPipes[1].getFileDescriptor()); 6019 while (toCopy > 0) { 6020 int toRead = (toCopy > mBuffer.length) 6021 ? mBuffer.length : (int)toCopy; 6022 int nRead = instream.read(mBuffer, 0, toRead); 6023 if (nRead >= 0) mBytes += nRead; 6024 if (nRead <= 0) break; 6025 toCopy -= nRead; 6026 6027 // send it to the output pipe as long as things 6028 // are still good 6029 if (pipeOkay) { 6030 try { 6031 pipe.write(mBuffer, 0, nRead); 6032 } catch (IOException e) { 6033 Slog.e(TAG, "Failed to write to restore pipe: " 6034 + e.getMessage()); 6035 pipeOkay = false; 6036 } 6037 } 6038 } 6039 6040 // done sending that file! Now we just need to consume 6041 // the delta from info.size to the end of block. 6042 skipTarPadding(info.size, instream); 6043 6044 // and now that we've sent it all, wait for the remote 6045 // side to acknowledge receipt 6046 agentSuccess = waitUntilOperationComplete(mEphemeralOpToken); 6047 } 6048 6049 // okay, if the remote end failed at any point, deal with 6050 // it by ignoring the rest of the restore on it 6051 if (!agentSuccess) { 6052 Slog.w(TAG, "Agent failure; ending restore"); 6053 mBackupHandler.removeMessages(MSG_RESTORE_OPERATION_TIMEOUT); 6054 tearDownPipes(); 6055 tearDownAgent(mTargetApp); 6056 mAgent = null; 6057 mPackagePolicies.put(pkg, RestorePolicy.IGNORE); 6058 6059 // If this was a single-package restore, we halt immediately 6060 // with an agent error under these circumstances 6061 if (mOnlyPackage != null) { 6062 setResult(RestoreEngine.TARGET_FAILURE); 6063 setRunning(false); 6064 return false; 6065 } 6066 } 6067 } 6068 6069 // Problems setting up the agent communication, an explicitly 6070 // dropped file, or an already-ignored package: skip to the 6071 // next stream entry by reading and discarding this file. 6072 if (!okay) { 6073 if (MORE_DEBUG) Slog.d(TAG, "[discarding file content]"); 6074 long bytesToConsume = (info.size + 511) & ~511; 6075 while (bytesToConsume > 0) { 6076 int toRead = (bytesToConsume > mBuffer.length) 6077 ? mBuffer.length : (int)bytesToConsume; 6078 long nRead = instream.read(mBuffer, 0, toRead); 6079 if (nRead >= 0) mBytes += nRead; 6080 if (nRead <= 0) break; 6081 bytesToConsume -= nRead; 6082 } 6083 } 6084 } 6085 } 6086 } catch (IOException e) { 6087 if (DEBUG) Slog.w(TAG, "io exception on restore socket read: " + e.getMessage()); 6088 setResult(RestoreEngine.TRANSPORT_FAILURE); 6089 info = null; 6090 } 6091 6092 // If we got here we're either running smoothly or we've finished 6093 if (info == null) { 6094 if (MORE_DEBUG) { 6095 Slog.i(TAG, "No [more] data for this package; tearing down"); 6096 } 6097 tearDownPipes(); 6098 setRunning(false); 6099 if (mustKillAgent) { 6100 tearDownAgent(mTargetApp); 6101 } 6102 } 6103 return (info != null); 6104 } 6105 6106 void setUpPipes() throws IOException { 6107 mPipes = ParcelFileDescriptor.createPipe(); 6108 } 6109 6110 void tearDownPipes() { 6111 // Teardown might arise from the inline restore processing or from the asynchronous 6112 // timeout mechanism, and these might race. Make sure we don't try to close and 6113 // null out the pipes twice. 6114 synchronized (this) { 6115 if (mPipes != null) { 6116 try { 6117 mPipes[0].close(); 6118 mPipes[0] = null; 6119 mPipes[1].close(); 6120 mPipes[1] = null; 6121 } catch (IOException e) { 6122 Slog.w(TAG, "Couldn't close agent pipes", e); 6123 } 6124 mPipes = null; 6125 } 6126 } 6127 } 6128 6129 void tearDownAgent(ApplicationInfo app) { 6130 if (mAgent != null) { 6131 tearDownAgentAndKill(app); 6132 mAgent = null; 6133 } 6134 } 6135 6136 void handleTimeout() { 6137 tearDownPipes(); 6138 setResult(RestoreEngine.TARGET_FAILURE); 6139 setRunning(false); 6140 } 6141 6142 class RestoreInstallObserver extends PackageInstallObserver { 6143 final AtomicBoolean mDone = new AtomicBoolean(); 6144 String mPackageName; 6145 int mResult; 6146 6147 public void reset() { 6148 synchronized (mDone) { 6149 mDone.set(false); 6150 } 6151 } 6152 6153 public void waitForCompletion() { 6154 synchronized (mDone) { 6155 while (mDone.get() == false) { 6156 try { 6157 mDone.wait(); 6158 } catch (InterruptedException e) { } 6159 } 6160 } 6161 } 6162 6163 int getResult() { 6164 return mResult; 6165 } 6166 6167 @Override 6168 public void onPackageInstalled(String packageName, int returnCode, 6169 String msg, Bundle extras) { 6170 synchronized (mDone) { 6171 mResult = returnCode; 6172 mPackageName = packageName; 6173 mDone.set(true); 6174 mDone.notifyAll(); 6175 } 6176 } 6177 } 6178 6179 class RestoreDeleteObserver extends IPackageDeleteObserver.Stub { 6180 final AtomicBoolean mDone = new AtomicBoolean(); 6181 int mResult; 6182 6183 public void reset() { 6184 synchronized (mDone) { 6185 mDone.set(false); 6186 } 6187 } 6188 6189 public void waitForCompletion() { 6190 synchronized (mDone) { 6191 while (mDone.get() == false) { 6192 try { 6193 mDone.wait(); 6194 } catch (InterruptedException e) { } 6195 } 6196 } 6197 } 6198 6199 @Override 6200 public void packageDeleted(String packageName, int returnCode) throws RemoteException { 6201 synchronized (mDone) { 6202 mResult = returnCode; 6203 mDone.set(true); 6204 mDone.notifyAll(); 6205 } 6206 } 6207 } 6208 6209 final RestoreInstallObserver mInstallObserver = new RestoreInstallObserver(); 6210 final RestoreDeleteObserver mDeleteObserver = new RestoreDeleteObserver(); 6211 6212 boolean installApk(FileMetadata info, String installerPackage, InputStream instream) { 6213 boolean okay = true; 6214 6215 if (DEBUG) Slog.d(TAG, "Installing from backup: " + info.packageName); 6216 6217 // The file content is an .apk file. Copy it out to a staging location and 6218 // attempt to install it. 6219 File apkFile = new File(mDataDir, info.packageName); 6220 try { 6221 FileOutputStream apkStream = new FileOutputStream(apkFile); 6222 byte[] buffer = new byte[32 * 1024]; 6223 long size = info.size; 6224 while (size > 0) { 6225 long toRead = (buffer.length < size) ? buffer.length : size; 6226 int didRead = instream.read(buffer, 0, (int)toRead); 6227 if (didRead >= 0) mBytes += didRead; 6228 apkStream.write(buffer, 0, didRead); 6229 size -= didRead; 6230 } 6231 apkStream.close(); 6232 6233 // make sure the installer can read it 6234 apkFile.setReadable(true, false); 6235 6236 // Now install it 6237 Uri packageUri = Uri.fromFile(apkFile); 6238 mInstallObserver.reset(); 6239 mPackageManager.installPackage(packageUri, mInstallObserver, 6240 PackageManager.INSTALL_REPLACE_EXISTING | PackageManager.INSTALL_FROM_ADB, 6241 installerPackage); 6242 mInstallObserver.waitForCompletion(); 6243 6244 if (mInstallObserver.getResult() != PackageManager.INSTALL_SUCCEEDED) { 6245 // The only time we continue to accept install of data even if the 6246 // apk install failed is if we had already determined that we could 6247 // accept the data regardless. 6248 if (mPackagePolicies.get(info.packageName) != RestorePolicy.ACCEPT) { 6249 okay = false; 6250 } 6251 } else { 6252 // Okay, the install succeeded. Make sure it was the right app. 6253 boolean uninstall = false; 6254 if (!mInstallObserver.mPackageName.equals(info.packageName)) { 6255 Slog.w(TAG, "Restore stream claimed to include apk for " 6256 + info.packageName + " but apk was really " 6257 + mInstallObserver.mPackageName); 6258 // delete the package we just put in place; it might be fraudulent 6259 okay = false; 6260 uninstall = true; 6261 } else { 6262 try { 6263 PackageInfo pkg = mPackageManager.getPackageInfo(info.packageName, 6264 PackageManager.GET_SIGNATURES); 6265 if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) { 6266 Slog.w(TAG, "Restore stream contains apk of package " 6267 + info.packageName + " but it disallows backup/restore"); 6268 okay = false; 6269 } else { 6270 // So far so good -- do the signatures match the manifest? 6271 Signature[] sigs = mManifestSignatures.get(info.packageName); 6272 if (signaturesMatch(sigs, pkg)) { 6273 // If this is a system-uid app without a declared backup agent, 6274 // don't restore any of the file data. 6275 if ((pkg.applicationInfo.uid < Process.FIRST_APPLICATION_UID) 6276 && (pkg.applicationInfo.backupAgentName == null)) { 6277 Slog.w(TAG, "Installed app " + info.packageName 6278 + " has restricted uid and no agent"); 6279 okay = false; 6280 } 6281 } else { 6282 Slog.w(TAG, "Installed app " + info.packageName 6283 + " signatures do not match restore manifest"); 6284 okay = false; 6285 uninstall = true; 6286 } 6287 } 6288 } catch (NameNotFoundException e) { 6289 Slog.w(TAG, "Install of package " + info.packageName 6290 + " succeeded but now not found"); 6291 okay = false; 6292 } 6293 } 6294 6295 // If we're not okay at this point, we need to delete the package 6296 // that we just installed. 6297 if (uninstall) { 6298 mDeleteObserver.reset(); 6299 mPackageManager.deletePackage(mInstallObserver.mPackageName, 6300 mDeleteObserver, 0); 6301 mDeleteObserver.waitForCompletion(); 6302 } 6303 } 6304 } catch (IOException e) { 6305 Slog.e(TAG, "Unable to transcribe restored apk for install"); 6306 okay = false; 6307 } finally { 6308 apkFile.delete(); 6309 } 6310 6311 return okay; 6312 } 6313 6314 // Given an actual file content size, consume the post-content padding mandated 6315 // by the tar format. 6316 void skipTarPadding(long size, InputStream instream) throws IOException { 6317 long partial = (size + 512) % 512; 6318 if (partial > 0) { 6319 final int needed = 512 - (int)partial; 6320 if (MORE_DEBUG) { 6321 Slog.i(TAG, "Skipping tar padding: " + needed + " bytes"); 6322 } 6323 byte[] buffer = new byte[needed]; 6324 if (readExactly(instream, buffer, 0, needed) == needed) { 6325 mBytes += needed; 6326 } else throw new IOException("Unexpected EOF in padding"); 6327 } 6328 } 6329 6330 // Read a widget metadata file, returning the restored blob 6331 void readMetadata(FileMetadata info, InputStream instream) throws IOException { 6332 // Fail on suspiciously large widget dump files 6333 if (info.size > 64 * 1024) { 6334 throw new IOException("Metadata too big; corrupt? size=" + info.size); 6335 } 6336 6337 byte[] buffer = new byte[(int) info.size]; 6338 if (readExactly(instream, buffer, 0, (int)info.size) == info.size) { 6339 mBytes += info.size; 6340 } else throw new IOException("Unexpected EOF in widget data"); 6341 6342 String[] str = new String[1]; 6343 int offset = extractLine(buffer, 0, str); 6344 int version = Integer.parseInt(str[0]); 6345 if (version == BACKUP_MANIFEST_VERSION) { 6346 offset = extractLine(buffer, offset, str); 6347 final String pkg = str[0]; 6348 if (info.packageName.equals(pkg)) { 6349 // Data checks out -- the rest of the buffer is a concatenation of 6350 // binary blobs as described in the comment at writeAppWidgetData() 6351 ByteArrayInputStream bin = new ByteArrayInputStream(buffer, 6352 offset, buffer.length - offset); 6353 DataInputStream in = new DataInputStream(bin); 6354 while (bin.available() > 0) { 6355 int token = in.readInt(); 6356 int size = in.readInt(); 6357 if (size > 64 * 1024) { 6358 throw new IOException("Datum " 6359 + Integer.toHexString(token) 6360 + " too big; corrupt? size=" + info.size); 6361 } 6362 switch (token) { 6363 case BACKUP_WIDGET_METADATA_TOKEN: 6364 { 6365 if (MORE_DEBUG) { 6366 Slog.i(TAG, "Got widget metadata for " + info.packageName); 6367 } 6368 mWidgetData = new byte[size]; 6369 in.read(mWidgetData); 6370 break; 6371 } 6372 default: 6373 { 6374 if (DEBUG) { 6375 Slog.i(TAG, "Ignoring metadata blob " 6376 + Integer.toHexString(token) 6377 + " for " + info.packageName); 6378 } 6379 in.skipBytes(size); 6380 break; 6381 } 6382 } 6383 } 6384 } else { 6385 Slog.w(TAG, "Metadata mismatch: package " + info.packageName 6386 + " but widget data for " + pkg); 6387 6388 Bundle monitoringExtras = putMonitoringExtra(null, 6389 EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName); 6390 monitoringExtras = putMonitoringExtra(monitoringExtras, 6391 BackupManagerMonitor.EXTRA_LOG_WIDGET_PACKAGE_NAME, pkg); 6392 mMonitor = monitorEvent(mMonitor, 6393 BackupManagerMonitor.LOG_EVENT_ID_WIDGET_METADATA_MISMATCH, 6394 null, 6395 LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, 6396 monitoringExtras); 6397 } 6398 } else { 6399 Slog.w(TAG, "Unsupported metadata version " + version); 6400 6401 Bundle monitoringExtras = putMonitoringExtra(null, EXTRA_LOG_EVENT_PACKAGE_NAME, 6402 info.packageName); 6403 monitoringExtras = putMonitoringExtra(monitoringExtras, 6404 EXTRA_LOG_EVENT_PACKAGE_VERSION, version); 6405 mMonitor = monitorEvent(mMonitor, 6406 BackupManagerMonitor.LOG_EVENT_ID_WIDGET_UNKNOWN_VERSION, 6407 null, 6408 LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, 6409 monitoringExtras); 6410 } 6411 } 6412 6413 // Returns a policy constant 6414 RestorePolicy readAppManifest(FileMetadata info, InputStream instream) 6415 throws IOException { 6416 // Fail on suspiciously large manifest files 6417 if (info.size > 64 * 1024) { 6418 throw new IOException("Restore manifest too big; corrupt? size=" + info.size); 6419 } 6420 6421 byte[] buffer = new byte[(int) info.size]; 6422 if (MORE_DEBUG) { 6423 Slog.i(TAG, " readAppManifest() looking for " + info.size + " bytes, " 6424 + mBytes + " already consumed"); 6425 } 6426 if (readExactly(instream, buffer, 0, (int)info.size) == info.size) { 6427 mBytes += info.size; 6428 } else throw new IOException("Unexpected EOF in manifest"); 6429 6430 RestorePolicy policy = RestorePolicy.IGNORE; 6431 String[] str = new String[1]; 6432 int offset = 0; 6433 6434 try { 6435 offset = extractLine(buffer, offset, str); 6436 int version = Integer.parseInt(str[0]); 6437 if (version == BACKUP_MANIFEST_VERSION) { 6438 offset = extractLine(buffer, offset, str); 6439 String manifestPackage = str[0]; 6440 // TODO: handle <original-package> 6441 if (manifestPackage.equals(info.packageName)) { 6442 offset = extractLine(buffer, offset, str); 6443 version = Integer.parseInt(str[0]); // app version 6444 offset = extractLine(buffer, offset, str); 6445 // This is the platform version, which we don't use, but we parse it 6446 // as a safety against corruption in the manifest. 6447 Integer.parseInt(str[0]); 6448 offset = extractLine(buffer, offset, str); 6449 info.installerPackageName = (str[0].length() > 0) ? str[0] : null; 6450 offset = extractLine(buffer, offset, str); 6451 boolean hasApk = str[0].equals("1"); 6452 offset = extractLine(buffer, offset, str); 6453 int numSigs = Integer.parseInt(str[0]); 6454 if (numSigs > 0) { 6455 Signature[] sigs = new Signature[numSigs]; 6456 for (int i = 0; i < numSigs; i++) { 6457 offset = extractLine(buffer, offset, str); 6458 sigs[i] = new Signature(str[0]); 6459 } 6460 mManifestSignatures.put(info.packageName, sigs); 6461 6462 // Okay, got the manifest info we need... 6463 try { 6464 PackageInfo pkgInfo = mPackageManager.getPackageInfo( 6465 info.packageName, PackageManager.GET_SIGNATURES); 6466 // Fall through to IGNORE if the app explicitly disallows backup 6467 final int flags = pkgInfo.applicationInfo.flags; 6468 if ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0) { 6469 // Restore system-uid-space packages only if they have 6470 // defined a custom backup agent 6471 if ((pkgInfo.applicationInfo.uid >= Process.FIRST_APPLICATION_UID) 6472 || (pkgInfo.applicationInfo.backupAgentName != null)) { 6473 // Verify signatures against any installed version; if they 6474 // don't match, then we fall though and ignore the data. The 6475 // signatureMatch() method explicitly ignores the signature 6476 // check for packages installed on the system partition, because 6477 // such packages are signed with the platform cert instead of 6478 // the app developer's cert, so they're different on every 6479 // device. 6480 if (signaturesMatch(sigs, pkgInfo)) { 6481 if ((pkgInfo.applicationInfo.flags 6482 & ApplicationInfo.FLAG_RESTORE_ANY_VERSION) != 0) { 6483 Slog.i(TAG, "Package has restoreAnyVersion; taking data"); 6484 mMonitor = monitorEvent(mMonitor, 6485 LOG_EVENT_ID_RESTORE_ANY_VERSION, 6486 pkgInfo, 6487 LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, 6488 null); 6489 policy = RestorePolicy.ACCEPT; 6490 } else if (pkgInfo.versionCode >= version) { 6491 Slog.i(TAG, "Sig + version match; taking data"); 6492 policy = RestorePolicy.ACCEPT; 6493 mMonitor = monitorEvent(mMonitor, 6494 LOG_EVENT_ID_VERSIONS_MATCH, 6495 pkgInfo, 6496 LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, 6497 null); 6498 } else { 6499 // The data is from a newer version of the app than 6500 // is presently installed. That means we can only 6501 // use it if the matching apk is also supplied. 6502 if (mAllowApks) { 6503 Slog.i(TAG, "Data version " + version 6504 + " is newer than installed version " 6505 + pkgInfo.versionCode 6506 + " - requiring apk"); 6507 policy = RestorePolicy.ACCEPT_IF_APK; 6508 } else { 6509 Slog.i(TAG, "Data requires newer version " 6510 + version + "; ignoring"); 6511 mMonitor = monitorEvent(mMonitor, 6512 LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER, 6513 pkgInfo, 6514 LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, 6515 putMonitoringExtra(null, 6516 EXTRA_LOG_OLD_VERSION, 6517 version)); 6518 6519 policy = RestorePolicy.IGNORE; 6520 } 6521 } 6522 } else { 6523 Slog.w(TAG, "Restore manifest signatures do not match " 6524 + "installed application for " + info.packageName); 6525 mMonitor = monitorEvent(mMonitor, 6526 LOG_EVENT_ID_FULL_RESTORE_SIGNATURE_MISMATCH, 6527 pkgInfo, 6528 LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, 6529 null); 6530 } 6531 } else { 6532 Slog.w(TAG, "Package " + info.packageName 6533 + " is system level with no agent"); 6534 mMonitor = monitorEvent(mMonitor, 6535 LOG_EVENT_ID_SYSTEM_APP_NO_AGENT, 6536 pkgInfo, 6537 LOG_EVENT_CATEGORY_AGENT, 6538 null); 6539 } 6540 } else { 6541 if (DEBUG) Slog.i(TAG, "Restore manifest from " 6542 + info.packageName + " but allowBackup=false"); 6543 mMonitor = monitorEvent(mMonitor, 6544 LOG_EVENT_ID_FULL_RESTORE_ALLOW_BACKUP_FALSE, 6545 pkgInfo, 6546 LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, 6547 null); 6548 } 6549 } catch (NameNotFoundException e) { 6550 // Okay, the target app isn't installed. We can process 6551 // the restore properly only if the dataset provides the 6552 // apk file and we can successfully install it. 6553 if (mAllowApks) { 6554 if (DEBUG) Slog.i(TAG, "Package " + info.packageName 6555 + " not installed; requiring apk in dataset"); 6556 policy = RestorePolicy.ACCEPT_IF_APK; 6557 } else { 6558 policy = RestorePolicy.IGNORE; 6559 } 6560 Bundle monitoringExtras = putMonitoringExtra(null, 6561 EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName); 6562 monitoringExtras = putMonitoringExtra(monitoringExtras, 6563 EXTRA_LOG_POLICY_ALLOW_APKS, mAllowApks); 6564 mMonitor = monitorEvent(mMonitor, 6565 LOG_EVENT_ID_APK_NOT_INSTALLED, 6566 null, 6567 LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, 6568 monitoringExtras); 6569 } 6570 6571 if (policy == RestorePolicy.ACCEPT_IF_APK && !hasApk) { 6572 Slog.i(TAG, "Cannot restore package " + info.packageName 6573 + " without the matching .apk"); 6574 mMonitor = monitorEvent(mMonitor, 6575 LOG_EVENT_ID_CANNOT_RESTORE_WITHOUT_APK, 6576 null, 6577 LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, 6578 putMonitoringExtra(null, 6579 EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName)); 6580 } 6581 } else { 6582 Slog.i(TAG, "Missing signature on backed-up package " 6583 + info.packageName); 6584 mMonitor = monitorEvent(mMonitor, 6585 LOG_EVENT_ID_MISSING_SIGNATURE, 6586 null, 6587 LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, 6588 putMonitoringExtra(null, 6589 EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName)); 6590 } 6591 } else { 6592 Slog.i(TAG, "Expected package " + info.packageName 6593 + " but restore manifest claims " + manifestPackage); 6594 Bundle monitoringExtras = putMonitoringExtra(null, 6595 EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName); 6596 monitoringExtras = putMonitoringExtra(monitoringExtras, 6597 EXTRA_LOG_MANIFEST_PACKAGE_NAME, manifestPackage); 6598 mMonitor = monitorEvent(mMonitor, 6599 LOG_EVENT_ID_EXPECTED_DIFFERENT_PACKAGE, 6600 null, 6601 LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, 6602 monitoringExtras); 6603 } 6604 } else { 6605 Slog.i(TAG, "Unknown restore manifest version " + version 6606 + " for package " + info.packageName); 6607 Bundle monitoringExtras = putMonitoringExtra(null, 6608 EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName); 6609 monitoringExtras = putMonitoringExtra(monitoringExtras, 6610 EXTRA_LOG_EVENT_PACKAGE_VERSION, version); 6611 mMonitor = monitorEvent(mMonitor, 6612 BackupManagerMonitor.LOG_EVENT_ID_UNKNOWN_VERSION, 6613 null, 6614 LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, 6615 monitoringExtras); 6616 6617 } 6618 } catch (NumberFormatException e) { 6619 Slog.w(TAG, "Corrupt restore manifest for package " + info.packageName); 6620 mMonitor = monitorEvent(mMonitor, 6621 BackupManagerMonitor.LOG_EVENT_ID_CORRUPT_MANIFEST, 6622 null, 6623 LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, 6624 putMonitoringExtra(null, EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName)); 6625 } catch (IllegalArgumentException e) { 6626 Slog.w(TAG, e.getMessage()); 6627 } 6628 6629 return policy; 6630 } 6631 6632 // Builds a line from a byte buffer starting at 'offset', and returns 6633 // the index of the next unconsumed data in the buffer. 6634 int extractLine(byte[] buffer, int offset, String[] outStr) throws IOException { 6635 final int end = buffer.length; 6636 if (offset >= end) throw new IOException("Incomplete data"); 6637 6638 int pos; 6639 for (pos = offset; pos < end; pos++) { 6640 byte c = buffer[pos]; 6641 // at LF we declare end of line, and return the next char as the 6642 // starting point for the next time through 6643 if (c == '\n') { 6644 break; 6645 } 6646 } 6647 outStr[0] = new String(buffer, offset, pos - offset); 6648 pos++; // may be pointing an extra byte past the end but that's okay 6649 return pos; 6650 } 6651 6652 void dumpFileMetadata(FileMetadata info) { 6653 if (MORE_DEBUG) { 6654 StringBuilder b = new StringBuilder(128); 6655 6656 // mode string 6657 b.append((info.type == BackupAgent.TYPE_DIRECTORY) ? 'd' : '-'); 6658 b.append(((info.mode & 0400) != 0) ? 'r' : '-'); 6659 b.append(((info.mode & 0200) != 0) ? 'w' : '-'); 6660 b.append(((info.mode & 0100) != 0) ? 'x' : '-'); 6661 b.append(((info.mode & 0040) != 0) ? 'r' : '-'); 6662 b.append(((info.mode & 0020) != 0) ? 'w' : '-'); 6663 b.append(((info.mode & 0010) != 0) ? 'x' : '-'); 6664 b.append(((info.mode & 0004) != 0) ? 'r' : '-'); 6665 b.append(((info.mode & 0002) != 0) ? 'w' : '-'); 6666 b.append(((info.mode & 0001) != 0) ? 'x' : '-'); 6667 b.append(String.format(" %9d ", info.size)); 6668 6669 Date stamp = new Date(info.mtime); 6670 b.append(new SimpleDateFormat("MMM dd HH:mm:ss ").format(stamp)); 6671 6672 b.append(info.packageName); 6673 b.append(" :: "); 6674 b.append(info.domain); 6675 b.append(" :: "); 6676 b.append(info.path); 6677 6678 Slog.i(TAG, b.toString()); 6679 } 6680 } 6681 6682 // Consume a tar file header block [sequence] and accumulate the relevant metadata 6683 FileMetadata readTarHeaders(InputStream instream) throws IOException { 6684 byte[] block = new byte[512]; 6685 FileMetadata info = null; 6686 6687 boolean gotHeader = readTarHeader(instream, block); 6688 if (gotHeader) { 6689 try { 6690 // okay, presume we're okay, and extract the various metadata 6691 info = new FileMetadata(); 6692 info.size = extractRadix(block, 124, 12, 8); 6693 info.mtime = extractRadix(block, 136, 12, 8); 6694 info.mode = extractRadix(block, 100, 8, 8); 6695 6696 info.path = extractString(block, 345, 155); // prefix 6697 String path = extractString(block, 0, 100); 6698 if (path.length() > 0) { 6699 if (info.path.length() > 0) info.path += '/'; 6700 info.path += path; 6701 } 6702 6703 // tar link indicator field: 1 byte at offset 156 in the header. 6704 int typeChar = block[156]; 6705 if (typeChar == 'x') { 6706 // pax extended header, so we need to read that 6707 gotHeader = readPaxExtendedHeader(instream, info); 6708 if (gotHeader) { 6709 // and after a pax extended header comes another real header -- read 6710 // that to find the real file type 6711 gotHeader = readTarHeader(instream, block); 6712 } 6713 if (!gotHeader) throw new IOException("Bad or missing pax header"); 6714 6715 typeChar = block[156]; 6716 } 6717 6718 switch (typeChar) { 6719 case '0': info.type = BackupAgent.TYPE_FILE; break; 6720 case '5': { 6721 info.type = BackupAgent.TYPE_DIRECTORY; 6722 if (info.size != 0) { 6723 Slog.w(TAG, "Directory entry with nonzero size in header"); 6724 info.size = 0; 6725 } 6726 break; 6727 } 6728 case 0: { 6729 // presume EOF 6730 if (MORE_DEBUG) Slog.w(TAG, "Saw type=0 in tar header block, info=" + info); 6731 return null; 6732 } 6733 default: { 6734 Slog.e(TAG, "Unknown tar entity type: " + typeChar); 6735 throw new IOException("Unknown entity type " + typeChar); 6736 } 6737 } 6738 6739 // Parse out the path 6740 // 6741 // first: apps/shared/unrecognized 6742 if (FullBackup.SHARED_PREFIX.regionMatches(0, 6743 info.path, 0, FullBackup.SHARED_PREFIX.length())) { 6744 // File in shared storage. !!! TODO: implement this. 6745 info.path = info.path.substring(FullBackup.SHARED_PREFIX.length()); 6746 info.packageName = SHARED_BACKUP_AGENT_PACKAGE; 6747 info.domain = FullBackup.SHARED_STORAGE_TOKEN; 6748 if (DEBUG) Slog.i(TAG, "File in shared storage: " + info.path); 6749 } else if (FullBackup.APPS_PREFIX.regionMatches(0, 6750 info.path, 0, FullBackup.APPS_PREFIX.length())) { 6751 // App content! Parse out the package name and domain 6752 6753 // strip the apps/ prefix 6754 info.path = info.path.substring(FullBackup.APPS_PREFIX.length()); 6755 6756 // extract the package name 6757 int slash = info.path.indexOf('/'); 6758 if (slash < 0) throw new IOException("Illegal semantic path in " + info.path); 6759 info.packageName = info.path.substring(0, slash); 6760 info.path = info.path.substring(slash+1); 6761 6762 // if it's a manifest or metadata payload we're done, otherwise parse 6763 // out the domain into which the file will be restored 6764 if (!info.path.equals(BACKUP_MANIFEST_FILENAME) 6765 && !info.path.equals(BACKUP_METADATA_FILENAME)) { 6766 slash = info.path.indexOf('/'); 6767 if (slash < 0) { 6768 throw new IOException("Illegal semantic path in non-manifest " 6769 + info.path); 6770 } 6771 info.domain = info.path.substring(0, slash); 6772 info.path = info.path.substring(slash + 1); 6773 } 6774 } 6775 } catch (IOException e) { 6776 if (DEBUG) { 6777 Slog.e(TAG, "Parse error in header: " + e.getMessage()); 6778 if (MORE_DEBUG) { 6779 HEXLOG(block); 6780 } 6781 } 6782 throw e; 6783 } 6784 } 6785 return info; 6786 } 6787 6788 private boolean isRestorableFile(FileMetadata info) { 6789 if (FullBackup.CACHE_TREE_TOKEN.equals(info.domain)) { 6790 if (MORE_DEBUG) { 6791 Slog.i(TAG, "Dropping cache file path " + info.path); 6792 } 6793 return false; 6794 } 6795 6796 if (FullBackup.ROOT_TREE_TOKEN.equals(info.domain)) { 6797 // It's possible this is "no-backup" dir contents in an archive stream 6798 // produced on a device running a version of the OS that predates that 6799 // API. Respect the no-backup intention and don't let the data get to 6800 // the app. 6801 if (info.path.startsWith("no_backup/")) { 6802 if (MORE_DEBUG) { 6803 Slog.i(TAG, "Dropping no_backup file path " + info.path); 6804 } 6805 return false; 6806 } 6807 } 6808 6809 // The path needs to be canonical 6810 if (info.path.contains("..") || info.path.contains("//")) { 6811 if (MORE_DEBUG) { 6812 Slog.w(TAG, "Dropping invalid path " + info.path); 6813 } 6814 return false; 6815 } 6816 6817 // Otherwise we think this file is good to go 6818 return true; 6819 } 6820 6821 private void HEXLOG(byte[] block) { 6822 int offset = 0; 6823 int todo = block.length; 6824 StringBuilder buf = new StringBuilder(64); 6825 while (todo > 0) { 6826 buf.append(String.format("%04x ", offset)); 6827 int numThisLine = (todo > 16) ? 16 : todo; 6828 for (int i = 0; i < numThisLine; i++) { 6829 buf.append(String.format("%02x ", block[offset+i])); 6830 } 6831 Slog.i("hexdump", buf.toString()); 6832 buf.setLength(0); 6833 todo -= numThisLine; 6834 offset += numThisLine; 6835 } 6836 } 6837 6838 // Read exactly the given number of bytes into a buffer at the stated offset. 6839 // Returns false if EOF is encountered before the requested number of bytes 6840 // could be read. 6841 int readExactly(InputStream in, byte[] buffer, int offset, int size) 6842 throws IOException { 6843 if (size <= 0) throw new IllegalArgumentException("size must be > 0"); 6844if (MORE_DEBUG) Slog.i(TAG, " ... readExactly(" + size + ") called"); 6845 int soFar = 0; 6846 while (soFar < size) { 6847 int nRead = in.read(buffer, offset + soFar, size - soFar); 6848 if (nRead <= 0) { 6849 if (MORE_DEBUG) Slog.w(TAG, "- wanted exactly " + size + " but got only " + soFar); 6850 break; 6851 } 6852 soFar += nRead; 6853if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soFar)); 6854 } 6855 return soFar; 6856 } 6857 6858 boolean readTarHeader(InputStream instream, byte[] block) throws IOException { 6859 final int got = readExactly(instream, block, 0, 512); 6860 if (got == 0) return false; // Clean EOF 6861 if (got < 512) throw new IOException("Unable to read full block header"); 6862 mBytes += 512; 6863 return true; 6864 } 6865 6866 // overwrites 'info' fields based on the pax extended header 6867 boolean readPaxExtendedHeader(InputStream instream, FileMetadata info) 6868 throws IOException { 6869 // We should never see a pax extended header larger than this 6870 if (info.size > 32*1024) { 6871 Slog.w(TAG, "Suspiciously large pax header size " + info.size 6872 + " - aborting"); 6873 throw new IOException("Sanity failure: pax header size " + info.size); 6874 } 6875 6876 // read whole blocks, not just the content size 6877 int numBlocks = (int)((info.size + 511) >> 9); 6878 byte[] data = new byte[numBlocks * 512]; 6879 if (readExactly(instream, data, 0, data.length) < data.length) { 6880 throw new IOException("Unable to read full pax header"); 6881 } 6882 mBytes += data.length; 6883 6884 final int contentSize = (int) info.size; 6885 int offset = 0; 6886 do { 6887 // extract the line at 'offset' 6888 int eol = offset+1; 6889 while (eol < contentSize && data[eol] != ' ') eol++; 6890 if (eol >= contentSize) { 6891 // error: we just hit EOD looking for the end of the size field 6892 throw new IOException("Invalid pax data"); 6893 } 6894 // eol points to the space between the count and the key 6895 int linelen = (int) extractRadix(data, offset, eol - offset, 10); 6896 int key = eol + 1; // start of key=value 6897 eol = offset + linelen - 1; // trailing LF 6898 int value; 6899 for (value = key+1; data[value] != '=' && value <= eol; value++); 6900 if (value > eol) { 6901 throw new IOException("Invalid pax declaration"); 6902 } 6903 6904 // pax requires that key/value strings be in UTF-8 6905 String keyStr = new String(data, key, value-key, "UTF-8"); 6906 // -1 to strip the trailing LF 6907 String valStr = new String(data, value+1, eol-value-1, "UTF-8"); 6908 6909 if ("path".equals(keyStr)) { 6910 info.path = valStr; 6911 } else if ("size".equals(keyStr)) { 6912 info.size = Long.parseLong(valStr); 6913 } else { 6914 if (DEBUG) Slog.i(TAG, "Unhandled pax key: " + key); 6915 } 6916 6917 offset += linelen; 6918 } while (offset < contentSize); 6919 6920 return true; 6921 } 6922 6923 long extractRadix(byte[] data, int offset, int maxChars, int radix) 6924 throws IOException { 6925 long value = 0; 6926 final int end = offset + maxChars; 6927 for (int i = offset; i < end; i++) { 6928 final byte b = data[i]; 6929 // Numeric fields in tar can terminate with either NUL or SPC 6930 if (b == 0 || b == ' ') break; 6931 if (b < '0' || b > ('0' + radix - 1)) { 6932 throw new IOException("Invalid number in header: '" + (char)b 6933 + "' for radix " + radix); 6934 } 6935 value = radix * value + (b - '0'); 6936 } 6937 return value; 6938 } 6939 6940 String extractString(byte[] data, int offset, int maxChars) throws IOException { 6941 final int end = offset + maxChars; 6942 int eos = offset; 6943 // tar string fields terminate early with a NUL 6944 while (eos < end && data[eos] != 0) eos++; 6945 return new String(data, offset, eos-offset, "US-ASCII"); 6946 } 6947 6948 void sendStartRestore() { 6949 if (mObserver != null) { 6950 try { 6951 mObserver.onStartRestore(); 6952 } catch (RemoteException e) { 6953 Slog.w(TAG, "full restore observer went away: startRestore"); 6954 mObserver = null; 6955 } 6956 } 6957 } 6958 6959 void sendOnRestorePackage(String name) { 6960 if (mObserver != null) { 6961 try { 6962 // TODO: use a more user-friendly name string 6963 mObserver.onRestorePackage(name); 6964 } catch (RemoteException e) { 6965 Slog.w(TAG, "full restore observer went away: restorePackage"); 6966 mObserver = null; 6967 } 6968 } 6969 } 6970 6971 void sendEndRestore() { 6972 if (mObserver != null) { 6973 try { 6974 mObserver.onEndRestore(); 6975 } catch (RemoteException e) { 6976 Slog.w(TAG, "full restore observer went away: endRestore"); 6977 mObserver = null; 6978 } 6979 } 6980 } 6981 } 6982 6983 // ***** end new engine class *** 6984 6985 // Used for synchronizing doRestoreFinished during adb restore 6986 class AdbRestoreFinishedLatch implements BackupRestoreTask { 6987 static final String TAG = "AdbRestoreFinishedLatch"; 6988 final CountDownLatch mLatch; 6989 private final int mCurrentOpToken; 6990 6991 AdbRestoreFinishedLatch(int currentOpToken) { 6992 mLatch = new CountDownLatch(1); 6993 mCurrentOpToken = currentOpToken; 6994 } 6995 6996 void await() { 6997 boolean latched = false; 6998 try { 6999 latched = mLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS); 7000 } catch (InterruptedException e) { 7001 Slog.w(TAG, "Interrupted!"); 7002 } 7003 } 7004 7005 @Override 7006 public void execute() { 7007 // Unused 7008 } 7009 7010 @Override 7011 public void operationComplete(long result) { 7012 if (MORE_DEBUG) { 7013 Slog.w(TAG, "adb onRestoreFinished() complete"); 7014 } 7015 mLatch.countDown(); 7016 removeOperation(mCurrentOpToken); 7017 } 7018 7019 @Override 7020 public void handleCancel(boolean cancelAll) { 7021 if (DEBUG) { 7022 Slog.w(TAG, "adb onRestoreFinished() timed out"); 7023 } 7024 mLatch.countDown(); 7025 removeOperation(mCurrentOpToken); 7026 } 7027 } 7028 7029 class PerformAdbRestoreTask implements Runnable { 7030 ParcelFileDescriptor mInputFile; 7031 String mCurrentPassword; 7032 String mDecryptPassword; 7033 IFullBackupRestoreObserver mObserver; 7034 AtomicBoolean mLatchObject; 7035 IBackupAgent mAgent; 7036 String mAgentPackage; 7037 ApplicationInfo mTargetApp; 7038 FullBackupObbConnection mObbConnection = null; 7039 ParcelFileDescriptor[] mPipes = null; 7040 byte[] mWidgetData = null; 7041 7042 long mBytes; 7043 7044 // Runner that can be placed on a separate thread to do in-process invocation 7045 // of the "restore finished" API asynchronously. Used by adb restore. 7046 class RestoreFinishedRunnable implements Runnable { 7047 final IBackupAgent mAgent; 7048 final int mToken; 7049 7050 RestoreFinishedRunnable(IBackupAgent agent, int token) { 7051 mAgent = agent; 7052 mToken = token; 7053 } 7054 7055 @Override 7056 public void run() { 7057 try { 7058 mAgent.doRestoreFinished(mToken, mBackupManagerBinder); 7059 } catch (RemoteException e) { 7060 // never happens; this is used only for local binder calls 7061 } 7062 } 7063 } 7064 7065 // possible handling states for a given package in the restore dataset 7066 final HashMap<String, RestorePolicy> mPackagePolicies 7067 = new HashMap<String, RestorePolicy>(); 7068 7069 // installer package names for each encountered app, derived from the manifests 7070 final HashMap<String, String> mPackageInstallers = new HashMap<String, String>(); 7071 7072 // Signatures for a given package found in its manifest file 7073 final HashMap<String, Signature[]> mManifestSignatures 7074 = new HashMap<String, Signature[]>(); 7075 7076 // Packages we've already wiped data on when restoring their first file 7077 final HashSet<String> mClearedPackages = new HashSet<String>(); 7078 7079 PerformAdbRestoreTask(ParcelFileDescriptor fd, String curPassword, String decryptPassword, 7080 IFullBackupRestoreObserver observer, AtomicBoolean latch) { 7081 mInputFile = fd; 7082 mCurrentPassword = curPassword; 7083 mDecryptPassword = decryptPassword; 7084 mObserver = observer; 7085 mLatchObject = latch; 7086 mAgent = null; 7087 mAgentPackage = null; 7088 mTargetApp = null; 7089 mObbConnection = new FullBackupObbConnection(); 7090 7091 // Which packages we've already wiped data on. We prepopulate this 7092 // with a whitelist of packages known to be unclearable. 7093 mClearedPackages.add("android"); 7094 mClearedPackages.add(SETTINGS_PACKAGE); 7095 } 7096 7097 class RestoreFileRunnable implements Runnable { 7098 IBackupAgent mAgent; 7099 FileMetadata mInfo; 7100 ParcelFileDescriptor mSocket; 7101 int mToken; 7102 7103 RestoreFileRunnable(IBackupAgent agent, FileMetadata info, 7104 ParcelFileDescriptor socket, int token) throws IOException { 7105 mAgent = agent; 7106 mInfo = info; 7107 mToken = token; 7108 7109 // This class is used strictly for process-local binder invocations. The 7110 // semantics of ParcelFileDescriptor differ in this case; in particular, we 7111 // do not automatically get a 'dup'ed descriptor that we can can continue 7112 // to use asynchronously from the caller. So, we make sure to dup it ourselves 7113 // before proceeding to do the restore. 7114 mSocket = ParcelFileDescriptor.dup(socket.getFileDescriptor()); 7115 } 7116 7117 @Override 7118 public void run() { 7119 try { 7120 mAgent.doRestoreFile(mSocket, mInfo.size, mInfo.type, 7121 mInfo.domain, mInfo.path, mInfo.mode, mInfo.mtime, 7122 mToken, mBackupManagerBinder); 7123 } catch (RemoteException e) { 7124 // never happens; this is used strictly for local binder calls 7125 } 7126 } 7127 } 7128 7129 @Override 7130 public void run() { 7131 Slog.i(TAG, "--- Performing full-dataset restore ---"); 7132 mObbConnection.establish(); 7133 sendStartRestore(); 7134 7135 // Are we able to restore shared-storage data? 7136 if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { 7137 mPackagePolicies.put(SHARED_BACKUP_AGENT_PACKAGE, RestorePolicy.ACCEPT); 7138 } 7139 7140 FileInputStream rawInStream = null; 7141 DataInputStream rawDataIn = null; 7142 try { 7143 if (!backupPasswordMatches(mCurrentPassword)) { 7144 if (DEBUG) Slog.w(TAG, "Backup password mismatch; aborting"); 7145 return; 7146 } 7147 7148 mBytes = 0; 7149 byte[] buffer = new byte[32 * 1024]; 7150 rawInStream = new FileInputStream(mInputFile.getFileDescriptor()); 7151 rawDataIn = new DataInputStream(rawInStream); 7152 7153 // First, parse out the unencrypted/uncompressed header 7154 boolean compressed = false; 7155 InputStream preCompressStream = rawInStream; 7156 final InputStream in; 7157 7158 boolean okay = false; 7159 final int headerLen = BACKUP_FILE_HEADER_MAGIC.length(); 7160 byte[] streamHeader = new byte[headerLen]; 7161 rawDataIn.readFully(streamHeader); 7162 byte[] magicBytes = BACKUP_FILE_HEADER_MAGIC.getBytes("UTF-8"); 7163 if (Arrays.equals(magicBytes, streamHeader)) { 7164 // okay, header looks good. now parse out the rest of the fields. 7165 String s = readHeaderLine(rawInStream); 7166 final int archiveVersion = Integer.parseInt(s); 7167 if (archiveVersion <= BACKUP_FILE_VERSION) { 7168 // okay, it's a version we recognize. if it's version 1, we may need 7169 // to try two different PBKDF2 regimes to compare checksums. 7170 final boolean pbkdf2Fallback = (archiveVersion == 1); 7171 7172 s = readHeaderLine(rawInStream); 7173 compressed = (Integer.parseInt(s) != 0); 7174 s = readHeaderLine(rawInStream); 7175 if (s.equals("none")) { 7176 // no more header to parse; we're good to go 7177 okay = true; 7178 } else if (mDecryptPassword != null && mDecryptPassword.length() > 0) { 7179 preCompressStream = decodeAesHeaderAndInitialize(s, pbkdf2Fallback, 7180 rawInStream); 7181 if (preCompressStream != null) { 7182 okay = true; 7183 } 7184 } else Slog.w(TAG, "Archive is encrypted but no password given"); 7185 } else Slog.w(TAG, "Wrong header version: " + s); 7186 } else Slog.w(TAG, "Didn't read the right header magic"); 7187 7188 if (!okay) { 7189 Slog.w(TAG, "Invalid restore data; aborting."); 7190 return; 7191 } 7192 7193 // okay, use the right stream layer based on compression 7194 in = (compressed) ? new InflaterInputStream(preCompressStream) : preCompressStream; 7195 7196 boolean didRestore; 7197 do { 7198 didRestore = restoreOneFile(in, buffer); 7199 } while (didRestore); 7200 7201 if (MORE_DEBUG) Slog.v(TAG, "Done consuming input tarfile, total bytes=" + mBytes); 7202 } catch (IOException e) { 7203 Slog.e(TAG, "Unable to read restore input"); 7204 } finally { 7205 tearDownPipes(); 7206 tearDownAgent(mTargetApp, true); 7207 7208 try { 7209 if (rawDataIn != null) rawDataIn.close(); 7210 if (rawInStream != null) rawInStream.close(); 7211 mInputFile.close(); 7212 } catch (IOException e) { 7213 Slog.w(TAG, "Close of restore data pipe threw", e); 7214 /* nothing we can do about this */ 7215 } 7216 synchronized (mLatchObject) { 7217 mLatchObject.set(true); 7218 mLatchObject.notifyAll(); 7219 } 7220 mObbConnection.tearDown(); 7221 sendEndRestore(); 7222 Slog.d(TAG, "Full restore pass complete."); 7223 mWakelock.release(); 7224 } 7225 } 7226 7227 String readHeaderLine(InputStream in) throws IOException { 7228 int c; 7229 StringBuilder buffer = new StringBuilder(80); 7230 while ((c = in.read()) >= 0) { 7231 if (c == '\n') break; // consume and discard the newlines 7232 buffer.append((char)c); 7233 } 7234 return buffer.toString(); 7235 } 7236 7237 InputStream attemptMasterKeyDecryption(String algorithm, byte[] userSalt, byte[] ckSalt, 7238 int rounds, String userIvHex, String masterKeyBlobHex, InputStream rawInStream, 7239 boolean doLog) { 7240 InputStream result = null; 7241 7242 try { 7243 Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding"); 7244 SecretKey userKey = buildPasswordKey(algorithm, mDecryptPassword, userSalt, 7245 rounds); 7246 byte[] IV = hexToByteArray(userIvHex); 7247 IvParameterSpec ivSpec = new IvParameterSpec(IV); 7248 c.init(Cipher.DECRYPT_MODE, 7249 new SecretKeySpec(userKey.getEncoded(), "AES"), 7250 ivSpec); 7251 byte[] mkCipher = hexToByteArray(masterKeyBlobHex); 7252 byte[] mkBlob = c.doFinal(mkCipher); 7253 7254 // first, the master key IV 7255 int offset = 0; 7256 int len = mkBlob[offset++]; 7257 IV = Arrays.copyOfRange(mkBlob, offset, offset + len); 7258 offset += len; 7259 // then the master key itself 7260 len = mkBlob[offset++]; 7261 byte[] mk = Arrays.copyOfRange(mkBlob, 7262 offset, offset + len); 7263 offset += len; 7264 // and finally the master key checksum hash 7265 len = mkBlob[offset++]; 7266 byte[] mkChecksum = Arrays.copyOfRange(mkBlob, 7267 offset, offset + len); 7268 7269 // now validate the decrypted master key against the checksum 7270 byte[] calculatedCk = makeKeyChecksum(algorithm, mk, ckSalt, rounds); 7271 if (Arrays.equals(calculatedCk, mkChecksum)) { 7272 ivSpec = new IvParameterSpec(IV); 7273 c.init(Cipher.DECRYPT_MODE, 7274 new SecretKeySpec(mk, "AES"), 7275 ivSpec); 7276 // Only if all of the above worked properly will 'result' be assigned 7277 result = new CipherInputStream(rawInStream, c); 7278 } else if (doLog) Slog.w(TAG, "Incorrect password"); 7279 } catch (InvalidAlgorithmParameterException e) { 7280 if (doLog) Slog.e(TAG, "Needed parameter spec unavailable!", e); 7281 } catch (BadPaddingException e) { 7282 // This case frequently occurs when the wrong password is used to decrypt 7283 // the master key. Use the identical "incorrect password" log text as is 7284 // used in the checksum failure log in order to avoid providing additional 7285 // information to an attacker. 7286 if (doLog) Slog.w(TAG, "Incorrect password"); 7287 } catch (IllegalBlockSizeException e) { 7288 if (doLog) Slog.w(TAG, "Invalid block size in master key"); 7289 } catch (NoSuchAlgorithmException e) { 7290 if (doLog) Slog.e(TAG, "Needed decryption algorithm unavailable!"); 7291 } catch (NoSuchPaddingException e) { 7292 if (doLog) Slog.e(TAG, "Needed padding mechanism unavailable!"); 7293 } catch (InvalidKeyException e) { 7294 if (doLog) Slog.w(TAG, "Illegal password; aborting"); 7295 } 7296 7297 return result; 7298 } 7299 7300 InputStream decodeAesHeaderAndInitialize(String encryptionName, boolean pbkdf2Fallback, 7301 InputStream rawInStream) { 7302 InputStream result = null; 7303 try { 7304 if (encryptionName.equals(ENCRYPTION_ALGORITHM_NAME)) { 7305 7306 String userSaltHex = readHeaderLine(rawInStream); // 5 7307 byte[] userSalt = hexToByteArray(userSaltHex); 7308 7309 String ckSaltHex = readHeaderLine(rawInStream); // 6 7310 byte[] ckSalt = hexToByteArray(ckSaltHex); 7311 7312 int rounds = Integer.parseInt(readHeaderLine(rawInStream)); // 7 7313 String userIvHex = readHeaderLine(rawInStream); // 8 7314 7315 String masterKeyBlobHex = readHeaderLine(rawInStream); // 9 7316 7317 // decrypt the master key blob 7318 result = attemptMasterKeyDecryption(PBKDF_CURRENT, userSalt, ckSalt, 7319 rounds, userIvHex, masterKeyBlobHex, rawInStream, false); 7320 if (result == null && pbkdf2Fallback) { 7321 result = attemptMasterKeyDecryption(PBKDF_FALLBACK, userSalt, ckSalt, 7322 rounds, userIvHex, masterKeyBlobHex, rawInStream, true); 7323 } 7324 } else Slog.w(TAG, "Unsupported encryption method: " + encryptionName); 7325 } catch (NumberFormatException e) { 7326 Slog.w(TAG, "Can't parse restore data header"); 7327 } catch (IOException e) { 7328 Slog.w(TAG, "Can't read input header"); 7329 } 7330 7331 return result; 7332 } 7333 7334 boolean restoreOneFile(InputStream instream, byte[] buffer) { 7335 FileMetadata info; 7336 try { 7337 info = readTarHeaders(instream); 7338 if (info != null) { 7339 if (MORE_DEBUG) { 7340 dumpFileMetadata(info); 7341 } 7342 7343 final String pkg = info.packageName; 7344 if (!pkg.equals(mAgentPackage)) { 7345 // okay, change in package; set up our various 7346 // bookkeeping if we haven't seen it yet 7347 if (!mPackagePolicies.containsKey(pkg)) { 7348 mPackagePolicies.put(pkg, RestorePolicy.IGNORE); 7349 } 7350 7351 // Clean up the previous agent relationship if necessary, 7352 // and let the observer know we're considering a new app. 7353 if (mAgent != null) { 7354 if (DEBUG) Slog.d(TAG, "Saw new package; finalizing old one"); 7355 // Now we're really done 7356 tearDownPipes(); 7357 tearDownAgent(mTargetApp, true); 7358 mTargetApp = null; 7359 mAgentPackage = null; 7360 } 7361 } 7362 7363 if (info.path.equals(BACKUP_MANIFEST_FILENAME)) { 7364 mPackagePolicies.put(pkg, readAppManifest(info, instream)); 7365 mPackageInstallers.put(pkg, info.installerPackageName); 7366 // We've read only the manifest content itself at this point, 7367 // so consume the footer before looping around to the next 7368 // input file 7369 skipTarPadding(info.size, instream); 7370 sendOnRestorePackage(pkg); 7371 } else if (info.path.equals(BACKUP_METADATA_FILENAME)) { 7372 // Metadata blobs! 7373 readMetadata(info, instream); 7374 skipTarPadding(info.size, instream); 7375 } else { 7376 // Non-manifest, so it's actual file data. Is this a package 7377 // we're ignoring? 7378 boolean okay = true; 7379 RestorePolicy policy = mPackagePolicies.get(pkg); 7380 switch (policy) { 7381 case IGNORE: 7382 okay = false; 7383 break; 7384 7385 case ACCEPT_IF_APK: 7386 // If we're in accept-if-apk state, then the first file we 7387 // see MUST be the apk. 7388 if (info.domain.equals(FullBackup.APK_TREE_TOKEN)) { 7389 if (DEBUG) Slog.d(TAG, "APK file; installing"); 7390 // Try to install the app. 7391 String installerName = mPackageInstallers.get(pkg); 7392 okay = installApk(info, installerName, instream); 7393 // good to go; promote to ACCEPT 7394 mPackagePolicies.put(pkg, (okay) 7395 ? RestorePolicy.ACCEPT 7396 : RestorePolicy.IGNORE); 7397 // At this point we've consumed this file entry 7398 // ourselves, so just strip the tar footer and 7399 // go on to the next file in the input stream 7400 skipTarPadding(info.size, instream); 7401 return true; 7402 } else { 7403 // File data before (or without) the apk. We can't 7404 // handle it coherently in this case so ignore it. 7405 mPackagePolicies.put(pkg, RestorePolicy.IGNORE); 7406 okay = false; 7407 } 7408 break; 7409 7410 case ACCEPT: 7411 if (info.domain.equals(FullBackup.APK_TREE_TOKEN)) { 7412 if (DEBUG) Slog.d(TAG, "apk present but ACCEPT"); 7413 // we can take the data without the apk, so we 7414 // *want* to do so. skip the apk by declaring this 7415 // one file not-okay without changing the restore 7416 // policy for the package. 7417 okay = false; 7418 } 7419 break; 7420 7421 default: 7422 // Something has gone dreadfully wrong when determining 7423 // the restore policy from the manifest. Ignore the 7424 // rest of this package's data. 7425 Slog.e(TAG, "Invalid policy from manifest"); 7426 okay = false; 7427 mPackagePolicies.put(pkg, RestorePolicy.IGNORE); 7428 break; 7429 } 7430 7431 // The path needs to be canonical 7432 if (info.path.contains("..") || info.path.contains("//")) { 7433 if (MORE_DEBUG) { 7434 Slog.w(TAG, "Dropping invalid path " + info.path); 7435 } 7436 okay = false; 7437 } 7438 7439 // If the policy is satisfied, go ahead and set up to pipe the 7440 // data to the agent. 7441 if (DEBUG && okay && mAgent != null) { 7442 Slog.i(TAG, "Reusing existing agent instance"); 7443 } 7444 if (okay && mAgent == null) { 7445 if (DEBUG) Slog.d(TAG, "Need to launch agent for " + pkg); 7446 7447 try { 7448 mTargetApp = mPackageManager.getApplicationInfo(pkg, 0); 7449 7450 // If we haven't sent any data to this app yet, we probably 7451 // need to clear it first. Check that. 7452 if (!mClearedPackages.contains(pkg)) { 7453 // apps with their own backup agents are 7454 // responsible for coherently managing a full 7455 // restore. 7456 if (mTargetApp.backupAgentName == null) { 7457 if (DEBUG) Slog.d(TAG, "Clearing app data preparatory to full restore"); 7458 clearApplicationDataSynchronous(pkg); 7459 } else { 7460 if (DEBUG) Slog.d(TAG, "backup agent (" 7461 + mTargetApp.backupAgentName + ") => no clear"); 7462 } 7463 mClearedPackages.add(pkg); 7464 } else { 7465 if (DEBUG) Slog.d(TAG, "We've initialized this app already; no clear required"); 7466 } 7467 7468 // All set; now set up the IPC and launch the agent 7469 setUpPipes(); 7470 mAgent = bindToAgentSynchronous(mTargetApp, 7471 ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL); 7472 mAgentPackage = pkg; 7473 } catch (IOException e) { 7474 // fall through to error handling 7475 } catch (NameNotFoundException e) { 7476 // fall through to error handling 7477 } 7478 7479 if (mAgent == null) { 7480 if (DEBUG) Slog.d(TAG, "Unable to create agent for " + pkg); 7481 okay = false; 7482 tearDownPipes(); 7483 mPackagePolicies.put(pkg, RestorePolicy.IGNORE); 7484 } 7485 } 7486 7487 // Sanity check: make sure we never give data to the wrong app. This 7488 // should never happen but a little paranoia here won't go amiss. 7489 if (okay && !pkg.equals(mAgentPackage)) { 7490 Slog.e(TAG, "Restoring data for " + pkg 7491 + " but agent is for " + mAgentPackage); 7492 okay = false; 7493 } 7494 7495 // At this point we have an agent ready to handle the full 7496 // restore data as well as a pipe for sending data to 7497 // that agent. Tell the agent to start reading from the 7498 // pipe. 7499 if (okay) { 7500 boolean agentSuccess = true; 7501 long toCopy = info.size; 7502 final int token = generateToken(); 7503 try { 7504 prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL, null, 7505 OP_TYPE_RESTORE_WAIT); 7506 if (info.domain.equals(FullBackup.OBB_TREE_TOKEN)) { 7507 if (DEBUG) Slog.d(TAG, "Restoring OBB file for " + pkg 7508 + " : " + info.path); 7509 mObbConnection.restoreObbFile(pkg, mPipes[0], 7510 info.size, info.type, info.path, info.mode, 7511 info.mtime, token, mBackupManagerBinder); 7512 } else { 7513 if (DEBUG) Slog.d(TAG, "Invoking agent to restore file " 7514 + info.path); 7515 // fire up the app's agent listening on the socket. If 7516 // the agent is running in the system process we can't 7517 // just invoke it asynchronously, so we provide a thread 7518 // for it here. 7519 if (mTargetApp.processName.equals("system")) { 7520 Slog.d(TAG, "system process agent - spinning a thread"); 7521 RestoreFileRunnable runner = new RestoreFileRunnable( 7522 mAgent, info, mPipes[0], token); 7523 new Thread(runner, "restore-sys-runner").start(); 7524 } else { 7525 mAgent.doRestoreFile(mPipes[0], info.size, info.type, 7526 info.domain, info.path, info.mode, info.mtime, 7527 token, mBackupManagerBinder); 7528 } 7529 } 7530 } catch (IOException e) { 7531 // couldn't dup the socket for a process-local restore 7532 Slog.d(TAG, "Couldn't establish restore"); 7533 agentSuccess = false; 7534 okay = false; 7535 } catch (RemoteException e) { 7536 // whoops, remote entity went away. We'll eat the content 7537 // ourselves, then, and not copy it over. 7538 Slog.e(TAG, "Agent crashed during full restore"); 7539 agentSuccess = false; 7540 okay = false; 7541 } 7542 7543 // Copy over the data if the agent is still good 7544 if (okay) { 7545 boolean pipeOkay = true; 7546 FileOutputStream pipe = new FileOutputStream( 7547 mPipes[1].getFileDescriptor()); 7548 while (toCopy > 0) { 7549 int toRead = (toCopy > buffer.length) 7550 ? buffer.length : (int)toCopy; 7551 int nRead = instream.read(buffer, 0, toRead); 7552 if (nRead >= 0) mBytes += nRead; 7553 if (nRead <= 0) break; 7554 toCopy -= nRead; 7555 7556 // send it to the output pipe as long as things 7557 // are still good 7558 if (pipeOkay) { 7559 try { 7560 pipe.write(buffer, 0, nRead); 7561 } catch (IOException e) { 7562 Slog.e(TAG, "Failed to write to restore pipe", e); 7563 pipeOkay = false; 7564 } 7565 } 7566 } 7567 7568 // done sending that file! Now we just need to consume 7569 // the delta from info.size to the end of block. 7570 skipTarPadding(info.size, instream); 7571 7572 // and now that we've sent it all, wait for the remote 7573 // side to acknowledge receipt 7574 agentSuccess = waitUntilOperationComplete(token); 7575 } 7576 7577 // okay, if the remote end failed at any point, deal with 7578 // it by ignoring the rest of the restore on it 7579 if (!agentSuccess) { 7580 if (DEBUG) { 7581 Slog.d(TAG, "Agent failure restoring " + pkg + "; now ignoring"); 7582 } 7583 mBackupHandler.removeMessages(MSG_RESTORE_OPERATION_TIMEOUT); 7584 tearDownPipes(); 7585 tearDownAgent(mTargetApp, false); 7586 mPackagePolicies.put(pkg, RestorePolicy.IGNORE); 7587 } 7588 } 7589 7590 // Problems setting up the agent communication, or an already- 7591 // ignored package: skip to the next tar stream entry by 7592 // reading and discarding this file. 7593 if (!okay) { 7594 if (DEBUG) Slog.d(TAG, "[discarding file content]"); 7595 long bytesToConsume = (info.size + 511) & ~511; 7596 while (bytesToConsume > 0) { 7597 int toRead = (bytesToConsume > buffer.length) 7598 ? buffer.length : (int)bytesToConsume; 7599 long nRead = instream.read(buffer, 0, toRead); 7600 if (nRead >= 0) mBytes += nRead; 7601 if (nRead <= 0) break; 7602 bytesToConsume -= nRead; 7603 } 7604 } 7605 } 7606 } 7607 } catch (IOException e) { 7608 if (DEBUG) Slog.w(TAG, "io exception on restore socket read", e); 7609 // treat as EOF 7610 info = null; 7611 } 7612 7613 return (info != null); 7614 } 7615 7616 void setUpPipes() throws IOException { 7617 mPipes = ParcelFileDescriptor.createPipe(); 7618 } 7619 7620 void tearDownPipes() { 7621 if (mPipes != null) { 7622 try { 7623 mPipes[0].close(); 7624 mPipes[0] = null; 7625 mPipes[1].close(); 7626 mPipes[1] = null; 7627 } catch (IOException e) { 7628 Slog.w(TAG, "Couldn't close agent pipes", e); 7629 } 7630 mPipes = null; 7631 } 7632 } 7633 7634 void tearDownAgent(ApplicationInfo app, boolean doRestoreFinished) { 7635 if (mAgent != null) { 7636 try { 7637 // In the adb restore case, we do restore-finished here 7638 if (doRestoreFinished) { 7639 final int token = generateToken(); 7640 final AdbRestoreFinishedLatch latch = new AdbRestoreFinishedLatch(token); 7641 prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL, latch, 7642 OP_TYPE_RESTORE_WAIT); 7643 if (mTargetApp.processName.equals("system")) { 7644 if (MORE_DEBUG) { 7645 Slog.d(TAG, "system agent - restoreFinished on thread"); 7646 } 7647 Runnable runner = new RestoreFinishedRunnable(mAgent, token); 7648 new Thread(runner, "restore-sys-finished-runner").start(); 7649 } else { 7650 mAgent.doRestoreFinished(token, mBackupManagerBinder); 7651 } 7652 7653 latch.await(); 7654 } 7655 7656 // unbind and tidy up even on timeout or failure, just in case 7657 mActivityManager.unbindBackupAgent(app); 7658 7659 // The agent was running with a stub Application object, so shut it down. 7660 // !!! We hardcode the confirmation UI's package name here rather than use a 7661 // manifest flag! TODO something less direct. 7662 if (app.uid >= Process.FIRST_APPLICATION_UID 7663 && !app.packageName.equals("com.android.backupconfirm")) { 7664 if (DEBUG) Slog.d(TAG, "Killing host process"); 7665 mActivityManager.killApplicationProcess(app.processName, app.uid); 7666 } else { 7667 if (DEBUG) Slog.d(TAG, "Not killing after full restore"); 7668 } 7669 } catch (RemoteException e) { 7670 Slog.d(TAG, "Lost app trying to shut down"); 7671 } 7672 mAgent = null; 7673 } 7674 } 7675 7676 class RestoreInstallObserver extends PackageInstallObserver { 7677 final AtomicBoolean mDone = new AtomicBoolean(); 7678 String mPackageName; 7679 int mResult; 7680 7681 public void reset() { 7682 synchronized (mDone) { 7683 mDone.set(false); 7684 } 7685 } 7686 7687 public void waitForCompletion() { 7688 synchronized (mDone) { 7689 while (mDone.get() == false) { 7690 try { 7691 mDone.wait(); 7692 } catch (InterruptedException e) { } 7693 } 7694 } 7695 } 7696 7697 int getResult() { 7698 return mResult; 7699 } 7700 7701 @Override 7702 public void onPackageInstalled(String packageName, int returnCode, 7703 String msg, Bundle extras) { 7704 synchronized (mDone) { 7705 mResult = returnCode; 7706 mPackageName = packageName; 7707 mDone.set(true); 7708 mDone.notifyAll(); 7709 } 7710 } 7711 } 7712 7713 class RestoreDeleteObserver extends IPackageDeleteObserver.Stub { 7714 final AtomicBoolean mDone = new AtomicBoolean(); 7715 int mResult; 7716 7717 public void reset() { 7718 synchronized (mDone) { 7719 mDone.set(false); 7720 } 7721 } 7722 7723 public void waitForCompletion() { 7724 synchronized (mDone) { 7725 while (mDone.get() == false) { 7726 try { 7727 mDone.wait(); 7728 } catch (InterruptedException e) { } 7729 } 7730 } 7731 } 7732 7733 @Override 7734 public void packageDeleted(String packageName, int returnCode) throws RemoteException { 7735 synchronized (mDone) { 7736 mResult = returnCode; 7737 mDone.set(true); 7738 mDone.notifyAll(); 7739 } 7740 } 7741 } 7742 7743 final RestoreInstallObserver mInstallObserver = new RestoreInstallObserver(); 7744 final RestoreDeleteObserver mDeleteObserver = new RestoreDeleteObserver(); 7745 7746 boolean installApk(FileMetadata info, String installerPackage, InputStream instream) { 7747 boolean okay = true; 7748 7749 if (DEBUG) Slog.d(TAG, "Installing from backup: " + info.packageName); 7750 7751 // The file content is an .apk file. Copy it out to a staging location and 7752 // attempt to install it. 7753 File apkFile = new File(mDataDir, info.packageName); 7754 try { 7755 FileOutputStream apkStream = new FileOutputStream(apkFile); 7756 byte[] buffer = new byte[32 * 1024]; 7757 long size = info.size; 7758 while (size > 0) { 7759 long toRead = (buffer.length < size) ? buffer.length : size; 7760 int didRead = instream.read(buffer, 0, (int)toRead); 7761 if (didRead >= 0) mBytes += didRead; 7762 apkStream.write(buffer, 0, didRead); 7763 size -= didRead; 7764 } 7765 apkStream.close(); 7766 7767 // make sure the installer can read it 7768 apkFile.setReadable(true, false); 7769 7770 // Now install it 7771 Uri packageUri = Uri.fromFile(apkFile); 7772 mInstallObserver.reset(); 7773 mPackageManager.installPackage(packageUri, mInstallObserver, 7774 PackageManager.INSTALL_REPLACE_EXISTING | PackageManager.INSTALL_FROM_ADB, 7775 installerPackage); 7776 mInstallObserver.waitForCompletion(); 7777 7778 if (mInstallObserver.getResult() != PackageManager.INSTALL_SUCCEEDED) { 7779 // The only time we continue to accept install of data even if the 7780 // apk install failed is if we had already determined that we could 7781 // accept the data regardless. 7782 if (mPackagePolicies.get(info.packageName) != RestorePolicy.ACCEPT) { 7783 okay = false; 7784 } 7785 } else { 7786 // Okay, the install succeeded. Make sure it was the right app. 7787 boolean uninstall = false; 7788 if (!mInstallObserver.mPackageName.equals(info.packageName)) { 7789 Slog.w(TAG, "Restore stream claimed to include apk for " 7790 + info.packageName + " but apk was really " 7791 + mInstallObserver.mPackageName); 7792 // delete the package we just put in place; it might be fraudulent 7793 okay = false; 7794 uninstall = true; 7795 } else { 7796 try { 7797 PackageInfo pkg = mPackageManager.getPackageInfo(info.packageName, 7798 PackageManager.GET_SIGNATURES); 7799 if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) { 7800 Slog.w(TAG, "Restore stream contains apk of package " 7801 + info.packageName + " but it disallows backup/restore"); 7802 okay = false; 7803 } else { 7804 // So far so good -- do the signatures match the manifest? 7805 Signature[] sigs = mManifestSignatures.get(info.packageName); 7806 if (signaturesMatch(sigs, pkg)) { 7807 // If this is a system-uid app without a declared backup agent, 7808 // don't restore any of the file data. 7809 if ((pkg.applicationInfo.uid < Process.FIRST_APPLICATION_UID) 7810 && (pkg.applicationInfo.backupAgentName == null)) { 7811 Slog.w(TAG, "Installed app " + info.packageName 7812 + " has restricted uid and no agent"); 7813 okay = false; 7814 } 7815 } else { 7816 Slog.w(TAG, "Installed app " + info.packageName 7817 + " signatures do not match restore manifest"); 7818 okay = false; 7819 uninstall = true; 7820 } 7821 } 7822 } catch (NameNotFoundException e) { 7823 Slog.w(TAG, "Install of package " + info.packageName 7824 + " succeeded but now not found"); 7825 okay = false; 7826 } 7827 } 7828 7829 // If we're not okay at this point, we need to delete the package 7830 // that we just installed. 7831 if (uninstall) { 7832 mDeleteObserver.reset(); 7833 mPackageManager.deletePackage(mInstallObserver.mPackageName, 7834 mDeleteObserver, 0); 7835 mDeleteObserver.waitForCompletion(); 7836 } 7837 } 7838 } catch (IOException e) { 7839 Slog.e(TAG, "Unable to transcribe restored apk for install"); 7840 okay = false; 7841 } finally { 7842 apkFile.delete(); 7843 } 7844 7845 return okay; 7846 } 7847 7848 // Given an actual file content size, consume the post-content padding mandated 7849 // by the tar format. 7850 void skipTarPadding(long size, InputStream instream) throws IOException { 7851 long partial = (size + 512) % 512; 7852 if (partial > 0) { 7853 final int needed = 512 - (int)partial; 7854 byte[] buffer = new byte[needed]; 7855 if (readExactly(instream, buffer, 0, needed) == needed) { 7856 mBytes += needed; 7857 } else throw new IOException("Unexpected EOF in padding"); 7858 } 7859 } 7860 7861 // Read a widget metadata file, returning the restored blob 7862 void readMetadata(FileMetadata info, InputStream instream) throws IOException { 7863 // Fail on suspiciously large widget dump files 7864 if (info.size > 64 * 1024) { 7865 throw new IOException("Metadata too big; corrupt? size=" + info.size); 7866 } 7867 7868 byte[] buffer = new byte[(int) info.size]; 7869 if (readExactly(instream, buffer, 0, (int)info.size) == info.size) { 7870 mBytes += info.size; 7871 } else throw new IOException("Unexpected EOF in widget data"); 7872 7873 String[] str = new String[1]; 7874 int offset = extractLine(buffer, 0, str); 7875 int version = Integer.parseInt(str[0]); 7876 if (version == BACKUP_MANIFEST_VERSION) { 7877 offset = extractLine(buffer, offset, str); 7878 final String pkg = str[0]; 7879 if (info.packageName.equals(pkg)) { 7880 // Data checks out -- the rest of the buffer is a concatenation of 7881 // binary blobs as described in the comment at writeAppWidgetData() 7882 ByteArrayInputStream bin = new ByteArrayInputStream(buffer, 7883 offset, buffer.length - offset); 7884 DataInputStream in = new DataInputStream(bin); 7885 while (bin.available() > 0) { 7886 int token = in.readInt(); 7887 int size = in.readInt(); 7888 if (size > 64 * 1024) { 7889 throw new IOException("Datum " 7890 + Integer.toHexString(token) 7891 + " too big; corrupt? size=" + info.size); 7892 } 7893 switch (token) { 7894 case BACKUP_WIDGET_METADATA_TOKEN: 7895 { 7896 if (MORE_DEBUG) { 7897 Slog.i(TAG, "Got widget metadata for " + info.packageName); 7898 } 7899 mWidgetData = new byte[size]; 7900 in.read(mWidgetData); 7901 break; 7902 } 7903 default: 7904 { 7905 if (DEBUG) { 7906 Slog.i(TAG, "Ignoring metadata blob " 7907 + Integer.toHexString(token) 7908 + " for " + info.packageName); 7909 } 7910 in.skipBytes(size); 7911 break; 7912 } 7913 } 7914 } 7915 } else { 7916 Slog.w(TAG, "Metadata mismatch: package " + info.packageName 7917 + " but widget data for " + pkg); 7918 } 7919 } else { 7920 Slog.w(TAG, "Unsupported metadata version " + version); 7921 } 7922 } 7923 7924 // Returns a policy constant; takes a buffer arg to reduce memory churn 7925 RestorePolicy readAppManifest(FileMetadata info, InputStream instream) 7926 throws IOException { 7927 // Fail on suspiciously large manifest files 7928 if (info.size > 64 * 1024) { 7929 throw new IOException("Restore manifest too big; corrupt? size=" + info.size); 7930 } 7931 7932 byte[] buffer = new byte[(int) info.size]; 7933 if (readExactly(instream, buffer, 0, (int)info.size) == info.size) { 7934 mBytes += info.size; 7935 } else throw new IOException("Unexpected EOF in manifest"); 7936 7937 RestorePolicy policy = RestorePolicy.IGNORE; 7938 String[] str = new String[1]; 7939 int offset = 0; 7940 7941 try { 7942 offset = extractLine(buffer, offset, str); 7943 int version = Integer.parseInt(str[0]); 7944 if (version == BACKUP_MANIFEST_VERSION) { 7945 offset = extractLine(buffer, offset, str); 7946 String manifestPackage = str[0]; 7947 // TODO: handle <original-package> 7948 if (manifestPackage.equals(info.packageName)) { 7949 offset = extractLine(buffer, offset, str); 7950 version = Integer.parseInt(str[0]); // app version 7951 offset = extractLine(buffer, offset, str); 7952 // This is the platform version, which we don't use, but we parse it 7953 // as a safety against corruption in the manifest. 7954 Integer.parseInt(str[0]); 7955 offset = extractLine(buffer, offset, str); 7956 info.installerPackageName = (str[0].length() > 0) ? str[0] : null; 7957 offset = extractLine(buffer, offset, str); 7958 boolean hasApk = str[0].equals("1"); 7959 offset = extractLine(buffer, offset, str); 7960 int numSigs = Integer.parseInt(str[0]); 7961 if (numSigs > 0) { 7962 Signature[] sigs = new Signature[numSigs]; 7963 for (int i = 0; i < numSigs; i++) { 7964 offset = extractLine(buffer, offset, str); 7965 sigs[i] = new Signature(str[0]); 7966 } 7967 mManifestSignatures.put(info.packageName, sigs); 7968 7969 // Okay, got the manifest info we need... 7970 try { 7971 PackageInfo pkgInfo = mPackageManager.getPackageInfo( 7972 info.packageName, PackageManager.GET_SIGNATURES); 7973 // Fall through to IGNORE if the app explicitly disallows backup 7974 final int flags = pkgInfo.applicationInfo.flags; 7975 if ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0) { 7976 // Restore system-uid-space packages only if they have 7977 // defined a custom backup agent 7978 if ((pkgInfo.applicationInfo.uid >= Process.FIRST_APPLICATION_UID) 7979 || (pkgInfo.applicationInfo.backupAgentName != null)) { 7980 // Verify signatures against any installed version; if they 7981 // don't match, then we fall though and ignore the data. The 7982 // signatureMatch() method explicitly ignores the signature 7983 // check for packages installed on the system partition, because 7984 // such packages are signed with the platform cert instead of 7985 // the app developer's cert, so they're different on every 7986 // device. 7987 if (signaturesMatch(sigs, pkgInfo)) { 7988 if ((pkgInfo.applicationInfo.flags 7989 & ApplicationInfo.FLAG_RESTORE_ANY_VERSION) != 0) { 7990 Slog.i(TAG, "Package has restoreAnyVersion; taking data"); 7991 policy = RestorePolicy.ACCEPT; 7992 } else if (pkgInfo.versionCode >= version) { 7993 Slog.i(TAG, "Sig + version match; taking data"); 7994 policy = RestorePolicy.ACCEPT; 7995 } else { 7996 // The data is from a newer version of the app than 7997 // is presently installed. That means we can only 7998 // use it if the matching apk is also supplied. 7999 Slog.d(TAG, "Data version " + version 8000 + " is newer than installed version " 8001 + pkgInfo.versionCode + " - requiring apk"); 8002 policy = RestorePolicy.ACCEPT_IF_APK; 8003 } 8004 } else { 8005 Slog.w(TAG, "Restore manifest signatures do not match " 8006 + "installed application for " + info.packageName); 8007 } 8008 } else { 8009 Slog.w(TAG, "Package " + info.packageName 8010 + " is system level with no agent"); 8011 } 8012 } else { 8013 if (DEBUG) Slog.i(TAG, "Restore manifest from " 8014 + info.packageName + " but allowBackup=false"); 8015 } 8016 } catch (NameNotFoundException e) { 8017 // Okay, the target app isn't installed. We can process 8018 // the restore properly only if the dataset provides the 8019 // apk file and we can successfully install it. 8020 if (DEBUG) Slog.i(TAG, "Package " + info.packageName 8021 + " not installed; requiring apk in dataset"); 8022 policy = RestorePolicy.ACCEPT_IF_APK; 8023 } 8024 8025 if (policy == RestorePolicy.ACCEPT_IF_APK && !hasApk) { 8026 Slog.i(TAG, "Cannot restore package " + info.packageName 8027 + " without the matching .apk"); 8028 } 8029 } else { 8030 Slog.i(TAG, "Missing signature on backed-up package " 8031 + info.packageName); 8032 } 8033 } else { 8034 Slog.i(TAG, "Expected package " + info.packageName 8035 + " but restore manifest claims " + manifestPackage); 8036 } 8037 } else { 8038 Slog.i(TAG, "Unknown restore manifest version " + version 8039 + " for package " + info.packageName); 8040 } 8041 } catch (NumberFormatException e) { 8042 Slog.w(TAG, "Corrupt restore manifest for package " + info.packageName); 8043 } catch (IllegalArgumentException e) { 8044 Slog.w(TAG, e.getMessage()); 8045 } 8046 8047 return policy; 8048 } 8049 8050 // Builds a line from a byte buffer starting at 'offset', and returns 8051 // the index of the next unconsumed data in the buffer. 8052 int extractLine(byte[] buffer, int offset, String[] outStr) throws IOException { 8053 final int end = buffer.length; 8054 if (offset >= end) throw new IOException("Incomplete data"); 8055 8056 int pos; 8057 for (pos = offset; pos < end; pos++) { 8058 byte c = buffer[pos]; 8059 // at LF we declare end of line, and return the next char as the 8060 // starting point for the next time through 8061 if (c == '\n') { 8062 break; 8063 } 8064 } 8065 outStr[0] = new String(buffer, offset, pos - offset); 8066 pos++; // may be pointing an extra byte past the end but that's okay 8067 return pos; 8068 } 8069 8070 void dumpFileMetadata(FileMetadata info) { 8071 if (DEBUG) { 8072 StringBuilder b = new StringBuilder(128); 8073 8074 // mode string 8075 b.append((info.type == BackupAgent.TYPE_DIRECTORY) ? 'd' : '-'); 8076 b.append(((info.mode & 0400) != 0) ? 'r' : '-'); 8077 b.append(((info.mode & 0200) != 0) ? 'w' : '-'); 8078 b.append(((info.mode & 0100) != 0) ? 'x' : '-'); 8079 b.append(((info.mode & 0040) != 0) ? 'r' : '-'); 8080 b.append(((info.mode & 0020) != 0) ? 'w' : '-'); 8081 b.append(((info.mode & 0010) != 0) ? 'x' : '-'); 8082 b.append(((info.mode & 0004) != 0) ? 'r' : '-'); 8083 b.append(((info.mode & 0002) != 0) ? 'w' : '-'); 8084 b.append(((info.mode & 0001) != 0) ? 'x' : '-'); 8085 b.append(String.format(" %9d ", info.size)); 8086 8087 Date stamp = new Date(info.mtime); 8088 b.append(new SimpleDateFormat("MMM dd HH:mm:ss ").format(stamp)); 8089 8090 b.append(info.packageName); 8091 b.append(" :: "); 8092 b.append(info.domain); 8093 b.append(" :: "); 8094 b.append(info.path); 8095 8096 Slog.i(TAG, b.toString()); 8097 } 8098 } 8099 // Consume a tar file header block [sequence] and accumulate the relevant metadata 8100 FileMetadata readTarHeaders(InputStream instream) throws IOException { 8101 byte[] block = new byte[512]; 8102 FileMetadata info = null; 8103 8104 boolean gotHeader = readTarHeader(instream, block); 8105 if (gotHeader) { 8106 try { 8107 // okay, presume we're okay, and extract the various metadata 8108 info = new FileMetadata(); 8109 info.size = extractRadix(block, 124, 12, 8); 8110 info.mtime = extractRadix(block, 136, 12, 8); 8111 info.mode = extractRadix(block, 100, 8, 8); 8112 8113 info.path = extractString(block, 345, 155); // prefix 8114 String path = extractString(block, 0, 100); 8115 if (path.length() > 0) { 8116 if (info.path.length() > 0) info.path += '/'; 8117 info.path += path; 8118 } 8119 8120 // tar link indicator field: 1 byte at offset 156 in the header. 8121 int typeChar = block[156]; 8122 if (typeChar == 'x') { 8123 // pax extended header, so we need to read that 8124 gotHeader = readPaxExtendedHeader(instream, info); 8125 if (gotHeader) { 8126 // and after a pax extended header comes another real header -- read 8127 // that to find the real file type 8128 gotHeader = readTarHeader(instream, block); 8129 } 8130 if (!gotHeader) throw new IOException("Bad or missing pax header"); 8131 8132 typeChar = block[156]; 8133 } 8134 8135 switch (typeChar) { 8136 case '0': info.type = BackupAgent.TYPE_FILE; break; 8137 case '5': { 8138 info.type = BackupAgent.TYPE_DIRECTORY; 8139 if (info.size != 0) { 8140 Slog.w(TAG, "Directory entry with nonzero size in header"); 8141 info.size = 0; 8142 } 8143 break; 8144 } 8145 case 0: { 8146 // presume EOF 8147 if (DEBUG) Slog.w(TAG, "Saw type=0 in tar header block, info=" + info); 8148 return null; 8149 } 8150 default: { 8151 Slog.e(TAG, "Unknown tar entity type: " + typeChar); 8152 throw new IOException("Unknown entity type " + typeChar); 8153 } 8154 } 8155 8156 // Parse out the path 8157 // 8158 // first: apps/shared/unrecognized 8159 if (FullBackup.SHARED_PREFIX.regionMatches(0, 8160 info.path, 0, FullBackup.SHARED_PREFIX.length())) { 8161 // File in shared storage. !!! TODO: implement this. 8162 info.path = info.path.substring(FullBackup.SHARED_PREFIX.length()); 8163 info.packageName = SHARED_BACKUP_AGENT_PACKAGE; 8164 info.domain = FullBackup.SHARED_STORAGE_TOKEN; 8165 if (DEBUG) Slog.i(TAG, "File in shared storage: " + info.path); 8166 } else if (FullBackup.APPS_PREFIX.regionMatches(0, 8167 info.path, 0, FullBackup.APPS_PREFIX.length())) { 8168 // App content! Parse out the package name and domain 8169 8170 // strip the apps/ prefix 8171 info.path = info.path.substring(FullBackup.APPS_PREFIX.length()); 8172 8173 // extract the package name 8174 int slash = info.path.indexOf('/'); 8175 if (slash < 0) throw new IOException("Illegal semantic path in " + info.path); 8176 info.packageName = info.path.substring(0, slash); 8177 info.path = info.path.substring(slash+1); 8178 8179 // if it's a manifest or metadata payload we're done, otherwise parse 8180 // out the domain into which the file will be restored 8181 if (!info.path.equals(BACKUP_MANIFEST_FILENAME) 8182 && !info.path.equals(BACKUP_METADATA_FILENAME)) { 8183 slash = info.path.indexOf('/'); 8184 if (slash < 0) throw new IOException("Illegal semantic path in non-manifest " + info.path); 8185 info.domain = info.path.substring(0, slash); 8186 info.path = info.path.substring(slash + 1); 8187 } 8188 } 8189 } catch (IOException e) { 8190 if (DEBUG) { 8191 Slog.e(TAG, "Parse error in header: " + e.getMessage()); 8192 HEXLOG(block); 8193 } 8194 throw e; 8195 } 8196 } 8197 return info; 8198 } 8199 8200 private void HEXLOG(byte[] block) { 8201 int offset = 0; 8202 int todo = block.length; 8203 StringBuilder buf = new StringBuilder(64); 8204 while (todo > 0) { 8205 buf.append(String.format("%04x ", offset)); 8206 int numThisLine = (todo > 16) ? 16 : todo; 8207 for (int i = 0; i < numThisLine; i++) { 8208 buf.append(String.format("%02x ", block[offset+i])); 8209 } 8210 Slog.i("hexdump", buf.toString()); 8211 buf.setLength(0); 8212 todo -= numThisLine; 8213 offset += numThisLine; 8214 } 8215 } 8216 8217 // Read exactly the given number of bytes into a buffer at the stated offset. 8218 // Returns false if EOF is encountered before the requested number of bytes 8219 // could be read. 8220 int readExactly(InputStream in, byte[] buffer, int offset, int size) 8221 throws IOException { 8222 if (size <= 0) throw new IllegalArgumentException("size must be > 0"); 8223 8224 int soFar = 0; 8225 while (soFar < size) { 8226 int nRead = in.read(buffer, offset + soFar, size - soFar); 8227 if (nRead <= 0) { 8228 if (MORE_DEBUG) Slog.w(TAG, "- wanted exactly " + size + " but got only " + soFar); 8229 break; 8230 } 8231 soFar += nRead; 8232 } 8233 return soFar; 8234 } 8235 8236 boolean readTarHeader(InputStream instream, byte[] block) throws IOException { 8237 final int got = readExactly(instream, block, 0, 512); 8238 if (got == 0) return false; // Clean EOF 8239 if (got < 512) throw new IOException("Unable to read full block header"); 8240 mBytes += 512; 8241 return true; 8242 } 8243 8244 // overwrites 'info' fields based on the pax extended header 8245 boolean readPaxExtendedHeader(InputStream instream, FileMetadata info) 8246 throws IOException { 8247 // We should never see a pax extended header larger than this 8248 if (info.size > 32*1024) { 8249 Slog.w(TAG, "Suspiciously large pax header size " + info.size 8250 + " - aborting"); 8251 throw new IOException("Sanity failure: pax header size " + info.size); 8252 } 8253 8254 // read whole blocks, not just the content size 8255 int numBlocks = (int)((info.size + 511) >> 9); 8256 byte[] data = new byte[numBlocks * 512]; 8257 if (readExactly(instream, data, 0, data.length) < data.length) { 8258 throw new IOException("Unable to read full pax header"); 8259 } 8260 mBytes += data.length; 8261 8262 final int contentSize = (int) info.size; 8263 int offset = 0; 8264 do { 8265 // extract the line at 'offset' 8266 int eol = offset+1; 8267 while (eol < contentSize && data[eol] != ' ') eol++; 8268 if (eol >= contentSize) { 8269 // error: we just hit EOD looking for the end of the size field 8270 throw new IOException("Invalid pax data"); 8271 } 8272 // eol points to the space between the count and the key 8273 int linelen = (int) extractRadix(data, offset, eol - offset, 10); 8274 int key = eol + 1; // start of key=value 8275 eol = offset + linelen - 1; // trailing LF 8276 int value; 8277 for (value = key+1; data[value] != '=' && value <= eol; value++); 8278 if (value > eol) { 8279 throw new IOException("Invalid pax declaration"); 8280 } 8281 8282 // pax requires that key/value strings be in UTF-8 8283 String keyStr = new String(data, key, value-key, "UTF-8"); 8284 // -1 to strip the trailing LF 8285 String valStr = new String(data, value+1, eol-value-1, "UTF-8"); 8286 8287 if ("path".equals(keyStr)) { 8288 info.path = valStr; 8289 } else if ("size".equals(keyStr)) { 8290 info.size = Long.parseLong(valStr); 8291 } else { 8292 if (DEBUG) Slog.i(TAG, "Unhandled pax key: " + key); 8293 } 8294 8295 offset += linelen; 8296 } while (offset < contentSize); 8297 8298 return true; 8299 } 8300 8301 long extractRadix(byte[] data, int offset, int maxChars, int radix) 8302 throws IOException { 8303 long value = 0; 8304 final int end = offset + maxChars; 8305 for (int i = offset; i < end; i++) { 8306 final byte b = data[i]; 8307 // Numeric fields in tar can terminate with either NUL or SPC 8308 if (b == 0 || b == ' ') break; 8309 if (b < '0' || b > ('0' + radix - 1)) { 8310 throw new IOException("Invalid number in header: '" + (char)b + "' for radix " + radix); 8311 } 8312 value = radix * value + (b - '0'); 8313 } 8314 return value; 8315 } 8316 8317 String extractString(byte[] data, int offset, int maxChars) throws IOException { 8318 final int end = offset + maxChars; 8319 int eos = offset; 8320 // tar string fields terminate early with a NUL 8321 while (eos < end && data[eos] != 0) eos++; 8322 return new String(data, offset, eos-offset, "US-ASCII"); 8323 } 8324 8325 void sendStartRestore() { 8326 if (mObserver != null) { 8327 try { 8328 mObserver.onStartRestore(); 8329 } catch (RemoteException e) { 8330 Slog.w(TAG, "full restore observer went away: startRestore"); 8331 mObserver = null; 8332 } 8333 } 8334 } 8335 8336 void sendOnRestorePackage(String name) { 8337 if (mObserver != null) { 8338 try { 8339 // TODO: use a more user-friendly name string 8340 mObserver.onRestorePackage(name); 8341 } catch (RemoteException e) { 8342 Slog.w(TAG, "full restore observer went away: restorePackage"); 8343 mObserver = null; 8344 } 8345 } 8346 } 8347 8348 void sendEndRestore() { 8349 if (mObserver != null) { 8350 try { 8351 mObserver.onEndRestore(); 8352 } catch (RemoteException e) { 8353 Slog.w(TAG, "full restore observer went away: endRestore"); 8354 mObserver = null; 8355 } 8356 } 8357 } 8358 } 8359 8360 // ----- Restore handling ----- 8361 8362 // Old style: directly match the stored vs on device signature blocks 8363 static boolean signaturesMatch(Signature[] storedSigs, PackageInfo target) { 8364 if (target == null) { 8365 return false; 8366 } 8367 8368 // If the target resides on the system partition, we allow it to restore 8369 // data from the like-named package in a restore set even if the signatures 8370 // do not match. (Unlike general applications, those flashed to the system 8371 // partition will be signed with the device's platform certificate, so on 8372 // different phones the same system app will have different signatures.) 8373 if ((target.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { 8374 if (MORE_DEBUG) Slog.v(TAG, "System app " + target.packageName + " - skipping sig check"); 8375 return true; 8376 } 8377 8378 // Allow unsigned apps, but not signed on one device and unsigned on the other 8379 // !!! TODO: is this the right policy? 8380 Signature[] deviceSigs = target.signatures; 8381 if (MORE_DEBUG) Slog.v(TAG, "signaturesMatch(): stored=" + storedSigs 8382 + " device=" + deviceSigs); 8383 if ((storedSigs == null || storedSigs.length == 0) 8384 && (deviceSigs == null || deviceSigs.length == 0)) { 8385 return true; 8386 } 8387 if (storedSigs == null || deviceSigs == null) { 8388 return false; 8389 } 8390 8391 // !!! TODO: this demands that every stored signature match one 8392 // that is present on device, and does not demand the converse. 8393 // Is this this right policy? 8394 int nStored = storedSigs.length; 8395 int nDevice = deviceSigs.length; 8396 8397 for (int i=0; i < nStored; i++) { 8398 boolean match = false; 8399 for (int j=0; j < nDevice; j++) { 8400 if (storedSigs[i].equals(deviceSigs[j])) { 8401 match = true; 8402 break; 8403 } 8404 } 8405 if (!match) { 8406 return false; 8407 } 8408 } 8409 return true; 8410 } 8411 8412 // Used by both incremental and full restore 8413 void restoreWidgetData(String packageName, byte[] widgetData) { 8414 // Apply the restored widget state and generate the ID update for the app 8415 // TODO: http://b/22388012 8416 if (MORE_DEBUG) { 8417 Slog.i(TAG, "Incorporating restored widget data"); 8418 } 8419 AppWidgetBackupBridge.restoreWidgetState(packageName, widgetData, UserHandle.USER_SYSTEM); 8420 } 8421 8422 // ***************************** 8423 // NEW UNIFIED RESTORE IMPLEMENTATION 8424 // ***************************** 8425 8426 // states of the unified-restore state machine 8427 enum UnifiedRestoreState { 8428 INITIAL, 8429 RUNNING_QUEUE, 8430 RESTORE_KEYVALUE, 8431 RESTORE_FULL, 8432 RESTORE_FINISHED, 8433 FINAL 8434 } 8435 8436 class PerformUnifiedRestoreTask implements BackupRestoreTask { 8437 // Transport we're working with to do the restore 8438 private IBackupTransport mTransport; 8439 8440 // Where per-transport saved state goes 8441 File mStateDir; 8442 8443 // Restore observer; may be null 8444 private IRestoreObserver mObserver; 8445 8446 // BackuoManagerMonitor; may be null 8447 private IBackupManagerMonitor mMonitor; 8448 8449 // Token identifying the dataset to the transport 8450 private long mToken; 8451 8452 // When this is a restore-during-install, this is the token identifying the 8453 // operation to the Package Manager, and we must ensure that we let it know 8454 // when we're finished. 8455 private int mPmToken; 8456 8457 // When this is restore-during-install, we need to tell the package manager 8458 // whether we actually launched the app, because this affects notifications 8459 // around externally-visible state transitions. 8460 private boolean mDidLaunch; 8461 8462 // Is this a whole-system restore, i.e. are we establishing a new ancestral 8463 // dataset to base future restore-at-install operations from? 8464 private boolean mIsSystemRestore; 8465 8466 // If this is a single-package restore, what package are we interested in? 8467 private PackageInfo mTargetPackage; 8468 8469 // In all cases, the calculated list of packages that we are trying to restore 8470 private List<PackageInfo> mAcceptSet; 8471 8472 // Our bookkeeping about the ancestral dataset 8473 private PackageManagerBackupAgent mPmAgent; 8474 8475 // Currently-bound backup agent for restore + restoreFinished purposes 8476 private IBackupAgent mAgent; 8477 8478 // What sort of restore we're doing now 8479 private RestoreDescription mRestoreDescription; 8480 8481 // The package we're currently restoring 8482 private PackageInfo mCurrentPackage; 8483 8484 // Widget-related data handled as part of this restore operation 8485 private byte[] mWidgetData; 8486 8487 // Number of apps restored in this pass 8488 private int mCount; 8489 8490 // When did we start? 8491 private long mStartRealtime; 8492 8493 // State machine progress 8494 private UnifiedRestoreState mState; 8495 8496 // How are things going? 8497 private int mStatus; 8498 8499 // Done? 8500 private boolean mFinished; 8501 8502 // Key/value: bookkeeping about staged data and files for agent access 8503 private File mBackupDataName; 8504 private File mStageName; 8505 private File mSavedStateName; 8506 private File mNewStateName; 8507 ParcelFileDescriptor mBackupData; 8508 ParcelFileDescriptor mNewState; 8509 8510 private final int mEphemeralOpToken; 8511 8512 // Invariant: mWakelock is already held, and this task is responsible for 8513 // releasing it at the end of the restore operation. 8514 PerformUnifiedRestoreTask(IBackupTransport transport, IRestoreObserver observer, 8515 IBackupManagerMonitor monitor, long restoreSetToken, PackageInfo targetPackage, 8516 int pmToken, boolean isFullSystemRestore, String[] filterSet) { 8517 mEphemeralOpToken = generateToken(); 8518 mState = UnifiedRestoreState.INITIAL; 8519 mStartRealtime = SystemClock.elapsedRealtime(); 8520 8521 mTransport = transport; 8522 mObserver = observer; 8523 mMonitor = monitor; 8524 mToken = restoreSetToken; 8525 mPmToken = pmToken; 8526 mTargetPackage = targetPackage; 8527 mIsSystemRestore = isFullSystemRestore; 8528 mFinished = false; 8529 mDidLaunch = false; 8530 8531 if (targetPackage != null) { 8532 // Single package restore 8533 mAcceptSet = new ArrayList<PackageInfo>(); 8534 mAcceptSet.add(targetPackage); 8535 } else { 8536 // Everything possible, or a target set 8537 if (filterSet == null) { 8538 // We want everything and a pony 8539 List<PackageInfo> apps = 8540 PackageManagerBackupAgent.getStorableApplications(mPackageManager); 8541 filterSet = packagesToNames(apps); 8542 if (DEBUG) { 8543 Slog.i(TAG, "Full restore; asking about " + filterSet.length + " apps"); 8544 } 8545 } 8546 8547 mAcceptSet = new ArrayList<PackageInfo>(filterSet.length); 8548 8549 // Pro tem, we insist on moving the settings provider package to last place. 8550 // Keep track of whether it's in the list, and bump it down if so. We also 8551 // want to do the system package itself first if it's called for. 8552 boolean hasSystem = false; 8553 boolean hasSettings = false; 8554 for (int i = 0; i < filterSet.length; i++) { 8555 try { 8556 PackageInfo info = mPackageManager.getPackageInfo(filterSet[i], 0); 8557 if ("android".equals(info.packageName)) { 8558 hasSystem = true; 8559 continue; 8560 } 8561 if (SETTINGS_PACKAGE.equals(info.packageName)) { 8562 hasSettings = true; 8563 continue; 8564 } 8565 8566 if (appIsEligibleForBackup(info.applicationInfo)) { 8567 mAcceptSet.add(info); 8568 } 8569 } catch (NameNotFoundException e) { 8570 // requested package name doesn't exist; ignore it 8571 } 8572 } 8573 if (hasSystem) { 8574 try { 8575 mAcceptSet.add(0, mPackageManager.getPackageInfo("android", 0)); 8576 } catch (NameNotFoundException e) { 8577 // won't happen; we know a priori that it's valid 8578 } 8579 } 8580 if (hasSettings) { 8581 try { 8582 mAcceptSet.add(mPackageManager.getPackageInfo(SETTINGS_PACKAGE, 0)); 8583 } catch (NameNotFoundException e) { 8584 // this one is always valid too 8585 } 8586 } 8587 } 8588 8589 if (MORE_DEBUG) { 8590 Slog.v(TAG, "Restore; accept set size is " + mAcceptSet.size()); 8591 for (PackageInfo info : mAcceptSet) { 8592 Slog.v(TAG, " " + info.packageName); 8593 } 8594 } 8595 } 8596 8597 private String[] packagesToNames(List<PackageInfo> apps) { 8598 final int N = apps.size(); 8599 String[] names = new String[N]; 8600 for (int i = 0; i < N; i++) { 8601 names[i] = apps.get(i).packageName; 8602 } 8603 return names; 8604 } 8605 8606 // Execute one tick of whatever state machine the task implements 8607 @Override 8608 public void execute() { 8609 if (MORE_DEBUG) Slog.v(TAG, "*** Executing restore step " + mState); 8610 switch (mState) { 8611 case INITIAL: 8612 startRestore(); 8613 break; 8614 8615 case RUNNING_QUEUE: 8616 dispatchNextRestore(); 8617 break; 8618 8619 case RESTORE_KEYVALUE: 8620 restoreKeyValue(); 8621 break; 8622 8623 case RESTORE_FULL: 8624 restoreFull(); 8625 break; 8626 8627 case RESTORE_FINISHED: 8628 restoreFinished(); 8629 break; 8630 8631 case FINAL: 8632 if (!mFinished) finalizeRestore(); 8633 else { 8634 Slog.e(TAG, "Duplicate finish"); 8635 } 8636 mFinished = true; 8637 break; 8638 } 8639 } 8640 8641 /* 8642 * SKETCH OF OPERATION 8643 * 8644 * create one of these PerformUnifiedRestoreTask objects, telling it which 8645 * dataset & transport to address, and then parameters within the restore 8646 * operation: single target package vs many, etc. 8647 * 8648 * 1. transport.startRestore(token, list-of-packages). If we need @pm@ it is 8649 * always placed first and the settings provider always placed last [for now]. 8650 * 8651 * 1a [if we needed @pm@ then nextRestorePackage() and restore the PMBA inline] 8652 * 8653 * [ state change => RUNNING_QUEUE ] 8654 * 8655 * NOW ITERATE: 8656 * 8657 * { 3. t.nextRestorePackage() 8658 * 4. does the metadata for this package allow us to restore it? 8659 * does the on-disk app permit us to restore it? [re-check allowBackup etc] 8660 * 5. is this a key/value dataset? => key/value agent restore 8661 * [ state change => RESTORE_KEYVALUE ] 8662 * 5a. spin up agent 8663 * 5b. t.getRestoreData() to stage it properly 8664 * 5c. call into agent to perform restore 8665 * 5d. tear down agent 8666 * [ state change => RUNNING_QUEUE ] 8667 * 8668 * 6. else it's a stream dataset: 8669 * [ state change => RESTORE_FULL ] 8670 * 6a. instantiate the engine for a stream restore: engine handles agent lifecycles 8671 * 6b. spin off engine runner on separate thread 8672 * 6c. ITERATE getNextFullRestoreDataChunk() and copy data to engine runner socket 8673 * [ state change => RUNNING_QUEUE ] 8674 * } 8675 * 8676 * [ state change => FINAL ] 8677 * 8678 * 7. t.finishRestore(), release wakelock, etc. 8679 * 8680 * 8681 */ 8682 8683 // state INITIAL : set up for the restore and read the metadata if necessary 8684 private void startRestore() { 8685 sendStartRestore(mAcceptSet.size()); 8686 8687 // If we're starting a full-system restore, set up to begin widget ID remapping 8688 if (mIsSystemRestore) { 8689 // TODO: http://b/22388012 8690 AppWidgetBackupBridge.restoreStarting(UserHandle.USER_SYSTEM); 8691 } 8692 8693 try { 8694 String transportDir = mTransport.transportDirName(); 8695 mStateDir = new File(mBaseStateDir, transportDir); 8696 8697 // Fetch the current metadata from the dataset first 8698 PackageInfo pmPackage = new PackageInfo(); 8699 pmPackage.packageName = PACKAGE_MANAGER_SENTINEL; 8700 mAcceptSet.add(0, pmPackage); 8701 8702 PackageInfo[] packages = mAcceptSet.toArray(new PackageInfo[0]); 8703 mStatus = mTransport.startRestore(mToken, packages); 8704 if (mStatus != BackupTransport.TRANSPORT_OK) { 8705 Slog.e(TAG, "Transport error " + mStatus + "; no restore possible"); 8706 mStatus = BackupTransport.TRANSPORT_ERROR; 8707 executeNextState(UnifiedRestoreState.FINAL); 8708 return; 8709 } 8710 8711 RestoreDescription desc = mTransport.nextRestorePackage(); 8712 if (desc == null) { 8713 Slog.e(TAG, "No restore metadata available; halting"); 8714 mMonitor = monitorEvent(mMonitor, 8715 BackupManagerMonitor.LOG_EVENT_ID_NO_RESTORE_METADATA_AVAILABLE, 8716 mCurrentPackage, 8717 BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, null); 8718 mStatus = BackupTransport.TRANSPORT_ERROR; 8719 executeNextState(UnifiedRestoreState.FINAL); 8720 return; 8721 } 8722 if (!PACKAGE_MANAGER_SENTINEL.equals(desc.getPackageName())) { 8723 Slog.e(TAG, "Required package metadata but got " 8724 + desc.getPackageName()); 8725 mMonitor = monitorEvent(mMonitor, 8726 BackupManagerMonitor.LOG_EVENT_ID_NO_PM_METADATA_RECEIVED, 8727 mCurrentPackage, 8728 BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, null); 8729 mStatus = BackupTransport.TRANSPORT_ERROR; 8730 executeNextState(UnifiedRestoreState.FINAL); 8731 return; 8732 } 8733 8734 // Pull the Package Manager metadata from the restore set first 8735 mCurrentPackage = new PackageInfo(); 8736 mCurrentPackage.packageName = PACKAGE_MANAGER_SENTINEL; 8737 mPmAgent = new PackageManagerBackupAgent(mPackageManager, null); 8738 mAgent = IBackupAgent.Stub.asInterface(mPmAgent.onBind()); 8739 if (MORE_DEBUG) { 8740 Slog.v(TAG, "initiating restore for PMBA"); 8741 } 8742 initiateOneRestore(mCurrentPackage, 0); 8743 // The PM agent called operationComplete() already, because our invocation 8744 // of it is process-local and therefore synchronous. That means that the 8745 // next-state message (RUNNING_QUEUE) is already enqueued. Only if we're 8746 // unable to proceed with running the queue do we remove that pending 8747 // message and jump straight to the FINAL state. Because this was 8748 // synchronous we also know that we should cancel the pending timeout 8749 // message. 8750 mBackupHandler.removeMessages(MSG_RESTORE_OPERATION_TIMEOUT); 8751 8752 // Verify that the backup set includes metadata. If not, we can't do 8753 // signature/version verification etc, so we simply do not proceed with 8754 // the restore operation. 8755 if (!mPmAgent.hasMetadata()) { 8756 Slog.e(TAG, "PM agent has no metadata, so not restoring"); 8757 mMonitor = monitorEvent(mMonitor, 8758 BackupManagerMonitor.LOG_EVENT_ID_PM_AGENT_HAS_NO_METADATA, 8759 mCurrentPackage, 8760 BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, null); 8761 EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, 8762 PACKAGE_MANAGER_SENTINEL, 8763 "Package manager restore metadata missing"); 8764 mStatus = BackupTransport.TRANSPORT_ERROR; 8765 mBackupHandler.removeMessages(MSG_BACKUP_RESTORE_STEP, this); 8766 executeNextState(UnifiedRestoreState.FINAL); 8767 return; 8768 } 8769 8770 // Success; cache the metadata and continue as expected with the 8771 // next state already enqueued 8772 8773 } catch (Exception e) { 8774 // If we lost the transport at any time, halt 8775 Slog.e(TAG, "Unable to contact transport for restore: " + e.getMessage()); 8776 mMonitor = monitorEvent(mMonitor, 8777 BackupManagerMonitor.LOG_EVENT_ID_LOST_TRANSPORT, 8778 null, 8779 BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT, null); 8780 mStatus = BackupTransport.TRANSPORT_ERROR; 8781 mBackupHandler.removeMessages(MSG_BACKUP_RESTORE_STEP, this); 8782 executeNextState(UnifiedRestoreState.FINAL); 8783 return; 8784 } 8785 } 8786 8787 // state RUNNING_QUEUE : figure out what the next thing to be restored is, 8788 // and fire the appropriate next step 8789 private void dispatchNextRestore() { 8790 UnifiedRestoreState nextState = UnifiedRestoreState.FINAL; 8791 try { 8792 mRestoreDescription = mTransport.nextRestorePackage(); 8793 final String pkgName = (mRestoreDescription != null) 8794 ? mRestoreDescription.getPackageName() : null; 8795 if (pkgName == null) { 8796 Slog.e(TAG, "Failure getting next package name"); 8797 EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE); 8798 nextState = UnifiedRestoreState.FINAL; 8799 return; 8800 } else if (mRestoreDescription == RestoreDescription.NO_MORE_PACKAGES) { 8801 // Yay we've reached the end cleanly 8802 if (DEBUG) { 8803 Slog.v(TAG, "No more packages; finishing restore"); 8804 } 8805 int millis = (int) (SystemClock.elapsedRealtime() - mStartRealtime); 8806 EventLog.writeEvent(EventLogTags.RESTORE_SUCCESS, mCount, millis); 8807 nextState = UnifiedRestoreState.FINAL; 8808 return; 8809 } 8810 8811 if (DEBUG) { 8812 Slog.i(TAG, "Next restore package: " + mRestoreDescription); 8813 } 8814 sendOnRestorePackage(pkgName); 8815 8816 Metadata metaInfo = mPmAgent.getRestoredMetadata(pkgName); 8817 if (metaInfo == null) { 8818 Slog.e(TAG, "No metadata for " + pkgName); 8819 EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, pkgName, 8820 "Package metadata missing"); 8821 nextState = UnifiedRestoreState.RUNNING_QUEUE; 8822 return; 8823 } 8824 8825 try { 8826 mCurrentPackage = mPackageManager.getPackageInfo( 8827 pkgName, PackageManager.GET_SIGNATURES); 8828 } catch (NameNotFoundException e) { 8829 // Whoops, we thought we could restore this package but it 8830 // turns out not to be present. Skip it. 8831 Slog.e(TAG, "Package not present: " + pkgName); 8832 mMonitor = monitorEvent(mMonitor, 8833 BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_NOT_PRESENT, 8834 mCurrentPackage, 8835 BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, 8836 null); 8837 EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, pkgName, 8838 "Package missing on device"); 8839 nextState = UnifiedRestoreState.RUNNING_QUEUE; 8840 return; 8841 } 8842 8843 if (metaInfo.versionCode > mCurrentPackage.versionCode) { 8844 // Data is from a "newer" version of the app than we have currently 8845 // installed. If the app has not declared that it is prepared to 8846 // handle this case, we do not attempt the restore. 8847 if ((mCurrentPackage.applicationInfo.flags 8848 & ApplicationInfo.FLAG_RESTORE_ANY_VERSION) == 0) { 8849 String message = "Source version " + metaInfo.versionCode 8850 + " > installed version " + mCurrentPackage.versionCode; 8851 Slog.w(TAG, "Package " + pkgName + ": " + message); 8852 Bundle monitoringExtras = putMonitoringExtra(null, 8853 BackupManagerMonitor.EXTRA_LOG_RESTORE_VERSION, 8854 metaInfo.versionCode); 8855 monitoringExtras = putMonitoringExtra(monitoringExtras, 8856 BackupManagerMonitor.EXTRA_LOG_RESTORE_ANYWAY, false); 8857 mMonitor = monitorEvent(mMonitor, 8858 BackupManagerMonitor.LOG_EVENT_ID_RESTORE_VERSION_HIGHER, 8859 mCurrentPackage, 8860 BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, 8861 monitoringExtras); 8862 EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, 8863 pkgName, message); 8864 nextState = UnifiedRestoreState.RUNNING_QUEUE; 8865 return; 8866 } else { 8867 if (DEBUG) Slog.v(TAG, "Source version " + metaInfo.versionCode 8868 + " > installed version " + mCurrentPackage.versionCode 8869 + " but restoreAnyVersion"); 8870 Bundle monitoringExtras = putMonitoringExtra(null, 8871 BackupManagerMonitor.EXTRA_LOG_RESTORE_VERSION, 8872 metaInfo.versionCode); 8873 monitoringExtras = putMonitoringExtra(monitoringExtras, 8874 BackupManagerMonitor.EXTRA_LOG_RESTORE_ANYWAY, true); 8875 mMonitor = monitorEvent(mMonitor, 8876 BackupManagerMonitor.LOG_EVENT_ID_RESTORE_VERSION_HIGHER, 8877 mCurrentPackage, 8878 BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, 8879 monitoringExtras); 8880 } 8881 } 8882 8883 if (MORE_DEBUG) Slog.v(TAG, "Package " + pkgName 8884 + " restore version [" + metaInfo.versionCode 8885 + "] is compatible with installed version [" 8886 + mCurrentPackage.versionCode + "]"); 8887 8888 // Reset per-package preconditions and fire the appropriate next state 8889 mWidgetData = null; 8890 final int type = mRestoreDescription.getDataType(); 8891 if (type == RestoreDescription.TYPE_KEY_VALUE) { 8892 nextState = UnifiedRestoreState.RESTORE_KEYVALUE; 8893 } else if (type == RestoreDescription.TYPE_FULL_STREAM) { 8894 nextState = UnifiedRestoreState.RESTORE_FULL; 8895 } else { 8896 // Unknown restore type; ignore this package and move on 8897 Slog.e(TAG, "Unrecognized restore type " + type); 8898 nextState = UnifiedRestoreState.RUNNING_QUEUE; 8899 return; 8900 } 8901 } catch (Exception e) { 8902 Slog.e(TAG, "Can't get next restore target from transport; halting: " 8903 + e.getMessage()); 8904 EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE); 8905 nextState = UnifiedRestoreState.FINAL; 8906 return; 8907 } finally { 8908 executeNextState(nextState); 8909 } 8910 } 8911 8912 // state RESTORE_KEYVALUE : restore one package via key/value API set 8913 private void restoreKeyValue() { 8914 // Initiating the restore will pass responsibility for the state machine's 8915 // progress to the agent callback, so we do not always execute the 8916 // next state here. 8917 final String packageName = mCurrentPackage.packageName; 8918 // Validate some semantic requirements that apply in this way 8919 // only to the key/value restore API flow 8920 if (mCurrentPackage.applicationInfo.backupAgentName == null 8921 || "".equals(mCurrentPackage.applicationInfo.backupAgentName)) { 8922 if (MORE_DEBUG) { 8923 Slog.i(TAG, "Data exists for package " + packageName 8924 + " but app has no agent; skipping"); 8925 } 8926 mMonitor = monitorEvent(mMonitor, 8927 BackupManagerMonitor.LOG_EVENT_ID_APP_HAS_NO_AGENT, mCurrentPackage, 8928 BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT, null); 8929 EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName, 8930 "Package has no agent"); 8931 executeNextState(UnifiedRestoreState.RUNNING_QUEUE); 8932 return; 8933 } 8934 8935 Metadata metaInfo = mPmAgent.getRestoredMetadata(packageName); 8936 if (!BackupUtils.signaturesMatch(metaInfo.sigHashes, mCurrentPackage)) { 8937 Slog.w(TAG, "Signature mismatch restoring " + packageName); 8938 mMonitor = monitorEvent(mMonitor, 8939 BackupManagerMonitor.LOG_EVENT_ID_SIGNATURE_MISMATCH, mCurrentPackage, 8940 BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, null); 8941 EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName, 8942 "Signature mismatch"); 8943 executeNextState(UnifiedRestoreState.RUNNING_QUEUE); 8944 return; 8945 } 8946 8947 // Good to go! Set up and bind the agent... 8948 mAgent = bindToAgentSynchronous( 8949 mCurrentPackage.applicationInfo, 8950 ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL); 8951 if (mAgent == null) { 8952 Slog.w(TAG, "Can't find backup agent for " + packageName); 8953 mMonitor = monitorEvent(mMonitor, 8954 BackupManagerMonitor.LOG_EVENT_ID_CANT_FIND_AGENT, mCurrentPackage, 8955 BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, null); 8956 EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName, 8957 "Restore agent missing"); 8958 executeNextState(UnifiedRestoreState.RUNNING_QUEUE); 8959 return; 8960 } 8961 8962 // Whatever happens next, we've launched the target app now; remember that. 8963 mDidLaunch = true; 8964 8965 // And then finally start the restore on this agent 8966 try { 8967 initiateOneRestore(mCurrentPackage, metaInfo.versionCode); 8968 ++mCount; 8969 } catch (Exception e) { 8970 Slog.e(TAG, "Error when attempting restore: " + e.toString()); 8971 keyValueAgentErrorCleanup(); 8972 executeNextState(UnifiedRestoreState.RUNNING_QUEUE); 8973 } 8974 } 8975 8976 // Guts of a key/value restore operation 8977 void initiateOneRestore(PackageInfo app, int appVersionCode) { 8978 final String packageName = app.packageName; 8979 8980 if (DEBUG) Slog.d(TAG, "initiateOneRestore packageName=" + packageName); 8981 8982 // !!! TODO: get the dirs from the transport 8983 mBackupDataName = new File(mDataDir, packageName + ".restore"); 8984 mStageName = new File(mDataDir, packageName + ".stage"); 8985 mNewStateName = new File(mStateDir, packageName + ".new"); 8986 mSavedStateName = new File(mStateDir, packageName); 8987 8988 // don't stage the 'android' package where the wallpaper data lives. this is 8989 // an optimization: we know there's no widget data hosted/published by that 8990 // package, and this way we avoid doing a spurious copy of MB-sized wallpaper 8991 // data following the download. 8992 boolean staging = !packageName.equals("android"); 8993 ParcelFileDescriptor stage; 8994 File downloadFile = (staging) ? mStageName : mBackupDataName; 8995 8996 try { 8997 // Run the transport's restore pass 8998 stage = ParcelFileDescriptor.open(downloadFile, 8999 ParcelFileDescriptor.MODE_READ_WRITE | 9000 ParcelFileDescriptor.MODE_CREATE | 9001 ParcelFileDescriptor.MODE_TRUNCATE); 9002 9003 if (mTransport.getRestoreData(stage) != BackupTransport.TRANSPORT_OK) { 9004 // Transport-level failure, so we wind everything up and 9005 // terminate the restore operation. 9006 Slog.e(TAG, "Error getting restore data for " + packageName); 9007 EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE); 9008 stage.close(); 9009 downloadFile.delete(); 9010 executeNextState(UnifiedRestoreState.FINAL); 9011 return; 9012 } 9013 9014 // We have the data from the transport. Now we extract and strip 9015 // any per-package metadata (typically widget-related information) 9016 // if appropriate 9017 if (staging) { 9018 stage.close(); 9019 stage = ParcelFileDescriptor.open(downloadFile, 9020 ParcelFileDescriptor.MODE_READ_ONLY); 9021 9022 mBackupData = ParcelFileDescriptor.open(mBackupDataName, 9023 ParcelFileDescriptor.MODE_READ_WRITE | 9024 ParcelFileDescriptor.MODE_CREATE | 9025 ParcelFileDescriptor.MODE_TRUNCATE); 9026 9027 BackupDataInput in = new BackupDataInput(stage.getFileDescriptor()); 9028 BackupDataOutput out = new BackupDataOutput(mBackupData.getFileDescriptor()); 9029 byte[] buffer = new byte[8192]; // will grow when needed 9030 while (in.readNextHeader()) { 9031 final String key = in.getKey(); 9032 final int size = in.getDataSize(); 9033 9034 // is this a special key? 9035 if (key.equals(KEY_WIDGET_STATE)) { 9036 if (DEBUG) { 9037 Slog.i(TAG, "Restoring widget state for " + packageName); 9038 } 9039 mWidgetData = new byte[size]; 9040 in.readEntityData(mWidgetData, 0, size); 9041 } else { 9042 if (size > buffer.length) { 9043 buffer = new byte[size]; 9044 } 9045 in.readEntityData(buffer, 0, size); 9046 out.writeEntityHeader(key, size); 9047 out.writeEntityData(buffer, size); 9048 } 9049 } 9050 9051 mBackupData.close(); 9052 } 9053 9054 // Okay, we have the data. Now have the agent do the restore. 9055 stage.close(); 9056 9057 mBackupData = ParcelFileDescriptor.open(mBackupDataName, 9058 ParcelFileDescriptor.MODE_READ_ONLY); 9059 9060 mNewState = ParcelFileDescriptor.open(mNewStateName, 9061 ParcelFileDescriptor.MODE_READ_WRITE | 9062 ParcelFileDescriptor.MODE_CREATE | 9063 ParcelFileDescriptor.MODE_TRUNCATE); 9064 9065 // Kick off the restore, checking for hung agents. The timeout or 9066 // the operationComplete() callback will schedule the next step, 9067 // so we do not do that here. 9068 prepareOperationTimeout(mEphemeralOpToken, TIMEOUT_RESTORE_INTERVAL, 9069 this, OP_TYPE_RESTORE_WAIT); 9070 mAgent.doRestore(mBackupData, appVersionCode, mNewState, 9071 mEphemeralOpToken, mBackupManagerBinder); 9072 } catch (Exception e) { 9073 Slog.e(TAG, "Unable to call app for restore: " + packageName, e); 9074 EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, 9075 packageName, e.toString()); 9076 keyValueAgentErrorCleanup(); // clears any pending timeout messages as well 9077 9078 // After a restore failure we go back to running the queue. If there 9079 // are no more packages to be restored that will be handled by the 9080 // next step. 9081 executeNextState(UnifiedRestoreState.RUNNING_QUEUE); 9082 } 9083 } 9084 9085 // state RESTORE_FULL : restore one package via streaming engine 9086 private void restoreFull() { 9087 // None of this can run on the work looper here, so we spin asynchronous 9088 // work like this: 9089 // 9090 // StreamFeederThread: read data from mTransport.getNextFullRestoreDataChunk() 9091 // write it into the pipe to the engine 9092 // EngineThread: FullRestoreEngine thread communicating with the target app 9093 // 9094 // When finished, StreamFeederThread executes next state as appropriate on the 9095 // backup looper, and the overall unified restore task resumes 9096 try { 9097 StreamFeederThread feeder = new StreamFeederThread(); 9098 if (MORE_DEBUG) { 9099 Slog.i(TAG, "Spinning threads for stream restore of " 9100 + mCurrentPackage.packageName); 9101 } 9102 new Thread(feeder, "unified-stream-feeder").start(); 9103 9104 // At this point the feeder is responsible for advancing the restore 9105 // state, so we're done here. 9106 } catch (IOException e) { 9107 // Unable to instantiate the feeder thread -- we need to bail on the 9108 // current target. We haven't asked the transport for data yet, though, 9109 // so we can do that simply by going back to running the restore queue. 9110 Slog.e(TAG, "Unable to construct pipes for stream restore!"); 9111 executeNextState(UnifiedRestoreState.RUNNING_QUEUE); 9112 } 9113 } 9114 9115 // state RESTORE_FINISHED : provide the "no more data" signpost callback at the end 9116 private void restoreFinished() { 9117 try { 9118 prepareOperationTimeout(mEphemeralOpToken, TIMEOUT_RESTORE_FINISHED_INTERVAL, this, 9119 OP_TYPE_RESTORE_WAIT); 9120 mAgent.doRestoreFinished(mEphemeralOpToken, mBackupManagerBinder); 9121 // If we get this far, the callback or timeout will schedule the 9122 // next restore state, so we're done 9123 } catch (Exception e) { 9124 final String packageName = mCurrentPackage.packageName; 9125 Slog.e(TAG, "Unable to finalize restore of " + packageName); 9126 EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, 9127 packageName, e.toString()); 9128 keyValueAgentErrorCleanup(); 9129 executeNextState(UnifiedRestoreState.RUNNING_QUEUE); 9130 } 9131 } 9132 9133 class StreamFeederThread extends RestoreEngine implements Runnable, BackupRestoreTask { 9134 final String TAG = "StreamFeederThread"; 9135 FullRestoreEngine mEngine; 9136 EngineThread mEngineThread; 9137 9138 // pipe through which we read data from the transport. [0] read, [1] write 9139 ParcelFileDescriptor[] mTransportPipes; 9140 9141 // pipe through which the engine will read data. [0] read, [1] write 9142 ParcelFileDescriptor[] mEnginePipes; 9143 9144 private final int mEphemeralOpToken; 9145 9146 public StreamFeederThread() throws IOException { 9147 mEphemeralOpToken = generateToken(); 9148 mTransportPipes = ParcelFileDescriptor.createPipe(); 9149 mEnginePipes = ParcelFileDescriptor.createPipe(); 9150 setRunning(true); 9151 } 9152 9153 @Override 9154 public void run() { 9155 UnifiedRestoreState nextState = UnifiedRestoreState.RUNNING_QUEUE; 9156 int status = BackupTransport.TRANSPORT_OK; 9157 9158 EventLog.writeEvent(EventLogTags.FULL_RESTORE_PACKAGE, 9159 mCurrentPackage.packageName); 9160 9161 mEngine = new FullRestoreEngine(this, null, mMonitor, mCurrentPackage, false, false, mEphemeralOpToken); 9162 mEngineThread = new EngineThread(mEngine, mEnginePipes[0]); 9163 9164 ParcelFileDescriptor eWriteEnd = mEnginePipes[1]; 9165 ParcelFileDescriptor tReadEnd = mTransportPipes[0]; 9166 ParcelFileDescriptor tWriteEnd = mTransportPipes[1]; 9167 9168 int bufferSize = 32 * 1024; 9169 byte[] buffer = new byte[bufferSize]; 9170 FileOutputStream engineOut = new FileOutputStream(eWriteEnd.getFileDescriptor()); 9171 FileInputStream transportIn = new FileInputStream(tReadEnd.getFileDescriptor()); 9172 9173 // spin up the engine and start moving data to it 9174 new Thread(mEngineThread, "unified-restore-engine").start(); 9175 9176 try { 9177 while (status == BackupTransport.TRANSPORT_OK) { 9178 // have the transport write some of the restoring data to us 9179 int result = mTransport.getNextFullRestoreDataChunk(tWriteEnd); 9180 if (result > 0) { 9181 // The transport wrote this many bytes of restore data to the 9182 // pipe, so pass it along to the engine. 9183 if (MORE_DEBUG) { 9184 Slog.v(TAG, " <- transport provided chunk size " + result); 9185 } 9186 if (result > bufferSize) { 9187 bufferSize = result; 9188 buffer = new byte[bufferSize]; 9189 } 9190 int toCopy = result; 9191 while (toCopy > 0) { 9192 int n = transportIn.read(buffer, 0, toCopy); 9193 engineOut.write(buffer, 0, n); 9194 toCopy -= n; 9195 if (MORE_DEBUG) { 9196 Slog.v(TAG, " -> wrote " + n + " to engine, left=" + toCopy); 9197 } 9198 } 9199 } else if (result == BackupTransport.NO_MORE_DATA) { 9200 // Clean finish. Wind up and we're done! 9201 if (MORE_DEBUG) { 9202 Slog.i(TAG, "Got clean full-restore EOF for " 9203 + mCurrentPackage.packageName); 9204 } 9205 status = BackupTransport.TRANSPORT_OK; 9206 break; 9207 } else { 9208 // Transport reported some sort of failure; the fall-through 9209 // handling will deal properly with that. 9210 Slog.e(TAG, "Error " + result + " streaming restore for " 9211 + mCurrentPackage.packageName); 9212 EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE); 9213 status = result; 9214 } 9215 } 9216 if (MORE_DEBUG) Slog.v(TAG, "Done copying to engine, falling through"); 9217 } catch (IOException e) { 9218 // We lost our ability to communicate via the pipes. That's worrying 9219 // but potentially recoverable; abandon this package's restore but 9220 // carry on with the next restore target. 9221 Slog.e(TAG, "Unable to route data for restore"); 9222 EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, 9223 mCurrentPackage.packageName, "I/O error on pipes"); 9224 status = BackupTransport.AGENT_ERROR; 9225 } catch (Exception e) { 9226 // The transport threw; terminate the whole operation. Closing 9227 // the sockets will wake up the engine and it will then tidy up the 9228 // remote end. 9229 Slog.e(TAG, "Transport failed during restore: " + e.getMessage()); 9230 EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE); 9231 status = BackupTransport.TRANSPORT_ERROR; 9232 } finally { 9233 // Close the transport pipes and *our* end of the engine pipe, 9234 // but leave the engine thread's end open so that it properly 9235 // hits EOF and winds up its operations. 9236 IoUtils.closeQuietly(mEnginePipes[1]); 9237 IoUtils.closeQuietly(mTransportPipes[0]); 9238 IoUtils.closeQuietly(mTransportPipes[1]); 9239 9240 // Don't proceed until the engine has wound up operations 9241 mEngineThread.waitForResult(); 9242 9243 // Now we're really done with this one too 9244 IoUtils.closeQuietly(mEnginePipes[0]); 9245 9246 // In all cases we want to remember whether we launched 9247 // the target app as part of our work so far. 9248 mDidLaunch = (mEngine.getAgent() != null); 9249 9250 // If we hit a transport-level error, we are done with everything; 9251 // if we hit an agent error we just go back to running the queue. 9252 if (status == BackupTransport.TRANSPORT_OK) { 9253 // Clean finish means we issue the restore-finished callback 9254 nextState = UnifiedRestoreState.RESTORE_FINISHED; 9255 9256 // the engine bound the target's agent, so recover that binding 9257 // to use for the callback. 9258 mAgent = mEngine.getAgent(); 9259 9260 // and the restored widget data, if any 9261 mWidgetData = mEngine.getWidgetData(); 9262 } else { 9263 // Something went wrong somewhere. Whether it was at the transport 9264 // level is immaterial; we need to tell the transport to bail 9265 try { 9266 mTransport.abortFullRestore(); 9267 } catch (Exception e) { 9268 // transport itself is dead; make sure we handle this as a 9269 // fatal error 9270 Slog.e(TAG, "Transport threw from abortFullRestore: " + e.getMessage()); 9271 status = BackupTransport.TRANSPORT_ERROR; 9272 } 9273 9274 // We also need to wipe the current target's data, as it's probably 9275 // in an incoherent state. 9276 clearApplicationDataSynchronous(mCurrentPackage.packageName); 9277 9278 // Schedule the next state based on the nature of our failure 9279 if (status == BackupTransport.TRANSPORT_ERROR) { 9280 nextState = UnifiedRestoreState.FINAL; 9281 } else { 9282 nextState = UnifiedRestoreState.RUNNING_QUEUE; 9283 } 9284 } 9285 executeNextState(nextState); 9286 setRunning(false); 9287 } 9288 } 9289 9290 // BackupRestoreTask interface, specifically for timeout handling 9291 9292 @Override 9293 public void execute() { /* intentionally empty */ } 9294 9295 @Override 9296 public void operationComplete(long result) { /* intentionally empty */ } 9297 9298 // The app has timed out handling a restoring file 9299 @Override 9300 public void handleCancel(boolean cancelAll) { 9301 removeOperation(mEphemeralOpToken); 9302 if (DEBUG) { 9303 Slog.w(TAG, "Full-data restore target timed out; shutting down"); 9304 } 9305 9306 mMonitor = monitorEvent(mMonitor, 9307 BackupManagerMonitor.LOG_EVENT_ID_FULL_RESTORE_TIMEOUT, 9308 mCurrentPackage, BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT, null); 9309 mEngineThread.handleTimeout(); 9310 9311 IoUtils.closeQuietly(mEnginePipes[1]); 9312 mEnginePipes[1] = null; 9313 IoUtils.closeQuietly(mEnginePipes[0]); 9314 mEnginePipes[0] = null; 9315 } 9316 } 9317 9318 class EngineThread implements Runnable { 9319 FullRestoreEngine mEngine; 9320 FileInputStream mEngineStream; 9321 9322 EngineThread(FullRestoreEngine engine, ParcelFileDescriptor engineSocket) { 9323 mEngine = engine; 9324 engine.setRunning(true); 9325 // We *do* want this FileInputStream to own the underlying fd, so that 9326 // when we are finished with it, it closes this end of the pipe in a way 9327 // that signals its other end. 9328 mEngineStream = new FileInputStream(engineSocket.getFileDescriptor(), true); 9329 } 9330 9331 public boolean isRunning() { 9332 return mEngine.isRunning(); 9333 } 9334 9335 public int waitForResult() { 9336 return mEngine.waitForResult(); 9337 } 9338 9339 @Override 9340 public void run() { 9341 try { 9342 while (mEngine.isRunning()) { 9343 // Tell it to be sure to leave the agent instance up after finishing 9344 mEngine.restoreOneFile(mEngineStream, false); 9345 } 9346 } finally { 9347 // Because mEngineStream adopted its underlying FD, this also 9348 // closes this end of the pipe. 9349 IoUtils.closeQuietly(mEngineStream); 9350 } 9351 } 9352 9353 public void handleTimeout() { 9354 IoUtils.closeQuietly(mEngineStream); 9355 mEngine.handleTimeout(); 9356 } 9357 } 9358 9359 // state FINAL : tear everything down and we're done. 9360 private void finalizeRestore() { 9361 if (MORE_DEBUG) Slog.d(TAG, "finishing restore mObserver=" + mObserver); 9362 9363 try { 9364 mTransport.finishRestore(); 9365 } catch (Exception e) { 9366 Slog.e(TAG, "Error finishing restore", e); 9367 } 9368 9369 // Tell the observer we're done 9370 if (mObserver != null) { 9371 try { 9372 mObserver.restoreFinished(mStatus); 9373 } catch (RemoteException e) { 9374 Slog.d(TAG, "Restore observer died at restoreFinished"); 9375 } 9376 } 9377 9378 // Clear any ongoing session timeout. 9379 mBackupHandler.removeMessages(MSG_RESTORE_SESSION_TIMEOUT); 9380 9381 // If we have a PM token, we must under all circumstances be sure to 9382 // handshake when we've finished. 9383 if (mPmToken > 0) { 9384 if (MORE_DEBUG) Slog.v(TAG, "finishing PM token " + mPmToken); 9385 try { 9386 mPackageManagerBinder.finishPackageInstall(mPmToken, mDidLaunch); 9387 } catch (RemoteException e) { /* can't happen */ } 9388 } else { 9389 // We were invoked via an active restore session, not by the Package 9390 // Manager, so start up the session timeout again. 9391 mBackupHandler.sendEmptyMessageDelayed(MSG_RESTORE_SESSION_TIMEOUT, 9392 TIMEOUT_RESTORE_INTERVAL); 9393 } 9394 9395 // Kick off any work that may be needed regarding app widget restores 9396 // TODO: http://b/22388012 9397 AppWidgetBackupBridge.restoreFinished(UserHandle.USER_SYSTEM); 9398 9399 // If this was a full-system restore, record the ancestral 9400 // dataset information 9401 if (mIsSystemRestore && mPmAgent != null) { 9402 mAncestralPackages = mPmAgent.getRestoredPackages(); 9403 mAncestralToken = mToken; 9404 writeRestoreTokens(); 9405 } 9406 9407 // done; we can finally release the wakelock and be legitimately done. 9408 Slog.i(TAG, "Restore complete."); 9409 9410 synchronized (mPendingRestores) { 9411 if (mPendingRestores.size() > 0) { 9412 if (DEBUG) { 9413 Slog.d(TAG, "Starting next pending restore."); 9414 } 9415 PerformUnifiedRestoreTask task = mPendingRestores.remove(); 9416 mBackupHandler.sendMessage( 9417 mBackupHandler.obtainMessage(MSG_BACKUP_RESTORE_STEP, task)); 9418 9419 } else { 9420 mIsRestoreInProgress = false; 9421 if (MORE_DEBUG) { 9422 Slog.d(TAG, "No pending restores."); 9423 } 9424 } 9425 } 9426 9427 mWakelock.release(); 9428 } 9429 9430 void keyValueAgentErrorCleanup() { 9431 // If the agent fails restore, it might have put the app's data 9432 // into an incoherent state. For consistency we wipe its data 9433 // again in this case before continuing with normal teardown 9434 clearApplicationDataSynchronous(mCurrentPackage.packageName); 9435 keyValueAgentCleanup(); 9436 } 9437 9438 // TODO: clean up naming; this is now used at finish by both k/v and stream restores 9439 void keyValueAgentCleanup() { 9440 mBackupDataName.delete(); 9441 mStageName.delete(); 9442 try { if (mBackupData != null) mBackupData.close(); } catch (IOException e) {} 9443 try { if (mNewState != null) mNewState.close(); } catch (IOException e) {} 9444 mBackupData = mNewState = null; 9445 9446 // if everything went okay, remember the recorded state now 9447 // 9448 // !!! TODO: the restored data could be migrated on the server 9449 // side into the current dataset. In that case the new state file 9450 // we just created would reflect the data already extant in the 9451 // backend, so there'd be nothing more to do. Until that happens, 9452 // however, we need to make sure that we record the data to the 9453 // current backend dataset. (Yes, this means shipping the data over 9454 // the wire in both directions. That's bad, but consistency comes 9455 // first, then efficiency.) Once we introduce server-side data 9456 // migration to the newly-restored device's dataset, we will change 9457 // the following from a discard of the newly-written state to the 9458 // "correct" operation of renaming into the canonical state blob. 9459 mNewStateName.delete(); // TODO: remove; see above comment 9460 //mNewStateName.renameTo(mSavedStateName); // TODO: replace with this 9461 9462 // If this wasn't the PM pseudopackage, tear down the agent side 9463 if (mCurrentPackage.applicationInfo != null) { 9464 // unbind and tidy up even on timeout or failure 9465 try { 9466 mActivityManager.unbindBackupAgent(mCurrentPackage.applicationInfo); 9467 9468 // The agent was probably running with a stub Application object, 9469 // which isn't a valid run mode for the main app logic. Shut 9470 // down the app so that next time it's launched, it gets the 9471 // usual full initialization. Note that this is only done for 9472 // full-system restores: when a single app has requested a restore, 9473 // it is explicitly not killed following that operation. 9474 // 9475 // We execute this kill when these conditions hold: 9476 // 1. it's not a system-uid process, 9477 // 2. the app did not request its own restore (mTargetPackage == null), and either 9478 // 3a. the app is a full-data target (TYPE_FULL_STREAM) or 9479 // b. the app does not state android:killAfterRestore="false" in its manifest 9480 final int appFlags = mCurrentPackage.applicationInfo.flags; 9481 final boolean killAfterRestore = 9482 (mCurrentPackage.applicationInfo.uid >= Process.FIRST_APPLICATION_UID) 9483 && ((mRestoreDescription.getDataType() == RestoreDescription.TYPE_FULL_STREAM) 9484 || ((appFlags & ApplicationInfo.FLAG_KILL_AFTER_RESTORE) != 0)); 9485 9486 if (mTargetPackage == null && killAfterRestore) { 9487 if (DEBUG) Slog.d(TAG, "Restore complete, killing host process of " 9488 + mCurrentPackage.applicationInfo.processName); 9489 mActivityManager.killApplicationProcess( 9490 mCurrentPackage.applicationInfo.processName, 9491 mCurrentPackage.applicationInfo.uid); 9492 } 9493 } catch (RemoteException e) { 9494 // can't happen; we run in the same process as the activity manager 9495 } 9496 } 9497 9498 // The caller is responsible for reestablishing the state machine; our 9499 // responsibility here is to clear the decks for whatever comes next. 9500 mBackupHandler.removeMessages(MSG_RESTORE_OPERATION_TIMEOUT, this); 9501 } 9502 9503 @Override 9504 public void operationComplete(long unusedResult) { 9505 removeOperation(mEphemeralOpToken); 9506 if (MORE_DEBUG) { 9507 Slog.i(TAG, "operationComplete() during restore: target=" 9508 + mCurrentPackage.packageName 9509 + " state=" + mState); 9510 } 9511 9512 final UnifiedRestoreState nextState; 9513 switch (mState) { 9514 case INITIAL: 9515 // We've just (manually) restored the PMBA. It doesn't need the 9516 // additional restore-finished callback so we bypass that and go 9517 // directly to running the queue. 9518 nextState = UnifiedRestoreState.RUNNING_QUEUE; 9519 break; 9520 9521 case RESTORE_KEYVALUE: 9522 case RESTORE_FULL: { 9523 // Okay, we've just heard back from the agent that it's done with 9524 // the restore itself. We now have to send the same agent its 9525 // doRestoreFinished() callback, so roll into that state. 9526 nextState = UnifiedRestoreState.RESTORE_FINISHED; 9527 break; 9528 } 9529 9530 case RESTORE_FINISHED: { 9531 // Okay, we're done with this package. Tidy up and go on to the next 9532 // app in the queue. 9533 int size = (int) mBackupDataName.length(); 9534 EventLog.writeEvent(EventLogTags.RESTORE_PACKAGE, 9535 mCurrentPackage.packageName, size); 9536 9537 // Just go back to running the restore queue 9538 keyValueAgentCleanup(); 9539 9540 // If there was widget state associated with this app, get the OS to 9541 // incorporate it into current bookeeping and then pass that along to 9542 // the app as part of the restore-time work. 9543 if (mWidgetData != null) { 9544 restoreWidgetData(mCurrentPackage.packageName, mWidgetData); 9545 } 9546 9547 nextState = UnifiedRestoreState.RUNNING_QUEUE; 9548 break; 9549 } 9550 9551 default: { 9552 // Some kind of horrible semantic error; we're in an unexpected state. 9553 // Back off hard and wind up. 9554 Slog.e(TAG, "Unexpected restore callback into state " + mState); 9555 keyValueAgentErrorCleanup(); 9556 nextState = UnifiedRestoreState.FINAL; 9557 break; 9558 } 9559 } 9560 9561 executeNextState(nextState); 9562 } 9563 9564 // A call to agent.doRestore() or agent.doRestoreFinished() has timed out 9565 @Override 9566 public void handleCancel(boolean cancelAll) { 9567 removeOperation(mEphemeralOpToken); 9568 Slog.e(TAG, "Timeout restoring application " + mCurrentPackage.packageName); 9569 mMonitor = monitorEvent(mMonitor, 9570 BackupManagerMonitor.LOG_EVENT_ID_KEY_VALUE_RESTORE_TIMEOUT, 9571 mCurrentPackage, BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT, null); 9572 EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, 9573 mCurrentPackage.packageName, "restore timeout"); 9574 // Handle like an agent that threw on invocation: wipe it and go on to the next 9575 keyValueAgentErrorCleanup(); 9576 executeNextState(UnifiedRestoreState.RUNNING_QUEUE); 9577 } 9578 9579 void executeNextState(UnifiedRestoreState nextState) { 9580 if (MORE_DEBUG) Slog.i(TAG, " => executing next step on " 9581 + this + " nextState=" + nextState); 9582 mState = nextState; 9583 Message msg = mBackupHandler.obtainMessage(MSG_BACKUP_RESTORE_STEP, this); 9584 mBackupHandler.sendMessage(msg); 9585 } 9586 9587 // restore observer support 9588 void sendStartRestore(int numPackages) { 9589 if (mObserver != null) { 9590 try { 9591 mObserver.restoreStarting(numPackages); 9592 } catch (RemoteException e) { 9593 Slog.w(TAG, "Restore observer went away: startRestore"); 9594 mObserver = null; 9595 } 9596 } 9597 } 9598 9599 void sendOnRestorePackage(String name) { 9600 if (mObserver != null) { 9601 if (mObserver != null) { 9602 try { 9603 mObserver.onUpdate(mCount, name); 9604 } catch (RemoteException e) { 9605 Slog.d(TAG, "Restore observer died in onUpdate"); 9606 mObserver = null; 9607 } 9608 } 9609 } 9610 } 9611 9612 void sendEndRestore() { 9613 if (mObserver != null) { 9614 try { 9615 mObserver.restoreFinished(mStatus); 9616 } catch (RemoteException e) { 9617 Slog.w(TAG, "Restore observer went away: endRestore"); 9618 mObserver = null; 9619 } 9620 } 9621 } 9622 } 9623 9624 class PerformClearTask implements Runnable { 9625 IBackupTransport mTransport; 9626 PackageInfo mPackage; 9627 9628 PerformClearTask(IBackupTransport transport, PackageInfo packageInfo) { 9629 mTransport = transport; 9630 mPackage = packageInfo; 9631 } 9632 9633 public void run() { 9634 try { 9635 // Clear the on-device backup state to ensure a full backup next time 9636 File stateDir = new File(mBaseStateDir, mTransport.transportDirName()); 9637 File stateFile = new File(stateDir, mPackage.packageName); 9638 stateFile.delete(); 9639 9640 // Tell the transport to remove all the persistent storage for the app 9641 // TODO - need to handle failures 9642 mTransport.clearBackupData(mPackage); 9643 } catch (Exception e) { 9644 Slog.e(TAG, "Transport threw clearing data for " + mPackage + ": " + e.getMessage()); 9645 } finally { 9646 try { 9647 // TODO - need to handle failures 9648 mTransport.finishBackup(); 9649 } catch (Exception e) { 9650 // Nothing we can do here, alas 9651 Slog.e(TAG, "Unable to mark clear operation finished: " + e.getMessage()); 9652 } 9653 9654 // Last but not least, release the cpu 9655 mWakelock.release(); 9656 } 9657 } 9658 } 9659 9660 class PerformInitializeTask implements Runnable { 9661 HashSet<String> mQueue; 9662 9663 PerformInitializeTask(HashSet<String> transportNames) { 9664 mQueue = transportNames; 9665 } 9666 9667 public void run() { 9668 try { 9669 for (String transportName : mQueue) { 9670 IBackupTransport transport = 9671 mTransportManager.getTransportBinder(transportName); 9672 if (transport == null) { 9673 Slog.e(TAG, "Requested init for " + transportName + " but not found"); 9674 continue; 9675 } 9676 9677 Slog.i(TAG, "Initializing (wiping) backup transport storage: " + transportName); 9678 EventLog.writeEvent(EventLogTags.BACKUP_START, transport.transportDirName()); 9679 long startRealtime = SystemClock.elapsedRealtime(); 9680 int status = transport.initializeDevice(); 9681 9682 if (status == BackupTransport.TRANSPORT_OK) { 9683 status = transport.finishBackup(); 9684 } 9685 9686 // Okay, the wipe really happened. Clean up our local bookkeeping. 9687 if (status == BackupTransport.TRANSPORT_OK) { 9688 Slog.i(TAG, "Device init successful"); 9689 int millis = (int) (SystemClock.elapsedRealtime() - startRealtime); 9690 EventLog.writeEvent(EventLogTags.BACKUP_INITIALIZE); 9691 resetBackupState(new File(mBaseStateDir, transport.transportDirName())); 9692 EventLog.writeEvent(EventLogTags.BACKUP_SUCCESS, 0, millis); 9693 synchronized (mQueueLock) { 9694 recordInitPendingLocked(false, transportName); 9695 } 9696 } else { 9697 // If this didn't work, requeue this one and try again 9698 // after a suitable interval 9699 Slog.e(TAG, "Transport error in initializeDevice()"); 9700 EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, "(initialize)"); 9701 synchronized (mQueueLock) { 9702 recordInitPendingLocked(true, transportName); 9703 } 9704 // do this via another alarm to make sure of the wakelock states 9705 long delay = transport.requestBackupTime(); 9706 Slog.w(TAG, "Init failed on " + transportName + " resched in " + delay); 9707 mAlarmManager.set(AlarmManager.RTC_WAKEUP, 9708 System.currentTimeMillis() + delay, mRunInitIntent); 9709 } 9710 } 9711 } catch (Exception e) { 9712 Slog.e(TAG, "Unexpected error performing init", e); 9713 } finally { 9714 // Done; release the wakelock 9715 mWakelock.release(); 9716 } 9717 } 9718 } 9719 9720 private void dataChangedImpl(String packageName) { 9721 HashSet<String> targets = dataChangedTargets(packageName); 9722 dataChangedImpl(packageName, targets); 9723 } 9724 9725 private void dataChangedImpl(String packageName, HashSet<String> targets) { 9726 // Record that we need a backup pass for the caller. Since multiple callers 9727 // may share a uid, we need to note all candidates within that uid and schedule 9728 // a backup pass for each of them. 9729 if (targets == null) { 9730 Slog.w(TAG, "dataChanged but no participant pkg='" + packageName + "'" 9731 + " uid=" + Binder.getCallingUid()); 9732 return; 9733 } 9734 9735 synchronized (mQueueLock) { 9736 // Note that this client has made data changes that need to be backed up 9737 if (targets.contains(packageName)) { 9738 // Add the caller to the set of pending backups. If there is 9739 // one already there, then overwrite it, but no harm done. 9740 BackupRequest req = new BackupRequest(packageName); 9741 if (mPendingBackups.put(packageName, req) == null) { 9742 if (MORE_DEBUG) Slog.d(TAG, "Now staging backup of " + packageName); 9743 9744 // Journal this request in case of crash. The put() 9745 // operation returned null when this package was not already 9746 // in the set; we want to avoid touching the disk redundantly. 9747 writeToJournalLocked(packageName); 9748 } 9749 } 9750 } 9751 9752 // ...and schedule a backup pass if necessary 9753 KeyValueBackupJob.schedule(mContext); 9754 } 9755 9756 // Note: packageName is currently unused, but may be in the future 9757 private HashSet<String> dataChangedTargets(String packageName) { 9758 // If the caller does not hold the BACKUP permission, it can only request a 9759 // backup of its own data. 9760 if ((mContext.checkPermission(android.Manifest.permission.BACKUP, Binder.getCallingPid(), 9761 Binder.getCallingUid())) == PackageManager.PERMISSION_DENIED) { 9762 synchronized (mBackupParticipants) { 9763 return mBackupParticipants.get(Binder.getCallingUid()); 9764 } 9765 } 9766 9767 // a caller with full permission can ask to back up any participating app 9768 HashSet<String> targets = new HashSet<String>(); 9769 if (PACKAGE_MANAGER_SENTINEL.equals(packageName)) { 9770 targets.add(PACKAGE_MANAGER_SENTINEL); 9771 } else { 9772 synchronized (mBackupParticipants) { 9773 int N = mBackupParticipants.size(); 9774 for (int i = 0; i < N; i++) { 9775 HashSet<String> s = mBackupParticipants.valueAt(i); 9776 if (s != null) { 9777 targets.addAll(s); 9778 } 9779 } 9780 } 9781 } 9782 return targets; 9783 } 9784 9785 private void writeToJournalLocked(String str) { 9786 RandomAccessFile out = null; 9787 try { 9788 if (mJournal == null) mJournal = File.createTempFile("journal", null, mJournalDir); 9789 out = new RandomAccessFile(mJournal, "rws"); 9790 out.seek(out.length()); 9791 out.writeUTF(str); 9792 } catch (IOException e) { 9793 Slog.e(TAG, "Can't write " + str + " to backup journal", e); 9794 mJournal = null; 9795 } finally { 9796 try { if (out != null) out.close(); } catch (IOException e) {} 9797 } 9798 } 9799 9800 // ----- IBackupManager binder interface ----- 9801 9802 public void dataChanged(final String packageName) { 9803 final int callingUserHandle = UserHandle.getCallingUserId(); 9804 if (callingUserHandle != UserHandle.USER_SYSTEM) { 9805 // TODO: http://b/22388012 9806 // App is running under a non-owner user profile. For now, we do not back 9807 // up data from secondary user profiles. 9808 // TODO: backups for all user profiles although don't add backup for profiles 9809 // without adding admin control in DevicePolicyManager. 9810 if (MORE_DEBUG) { 9811 Slog.v(TAG, "dataChanged(" + packageName + ") ignored because it's user " 9812 + callingUserHandle); 9813 } 9814 return; 9815 } 9816 9817 final HashSet<String> targets = dataChangedTargets(packageName); 9818 if (targets == null) { 9819 Slog.w(TAG, "dataChanged but no participant pkg='" + packageName + "'" 9820 + " uid=" + Binder.getCallingUid()); 9821 return; 9822 } 9823 9824 mBackupHandler.post(new Runnable() { 9825 public void run() { 9826 dataChangedImpl(packageName, targets); 9827 } 9828 }); 9829 } 9830 9831 // Clear the given package's backup data from the current transport 9832 public void clearBackupData(String transportName, String packageName) { 9833 if (DEBUG) Slog.v(TAG, "clearBackupData() of " + packageName + " on " + transportName); 9834 PackageInfo info; 9835 try { 9836 info = mPackageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES); 9837 } catch (NameNotFoundException e) { 9838 Slog.d(TAG, "No such package '" + packageName + "' - not clearing backup data"); 9839 return; 9840 } 9841 9842 // If the caller does not hold the BACKUP permission, it can only request a 9843 // wipe of its own backed-up data. 9844 HashSet<String> apps; 9845 if ((mContext.checkPermission(android.Manifest.permission.BACKUP, Binder.getCallingPid(), 9846 Binder.getCallingUid())) == PackageManager.PERMISSION_DENIED) { 9847 apps = mBackupParticipants.get(Binder.getCallingUid()); 9848 } else { 9849 // a caller with full permission can ask to back up any participating app 9850 // !!! TODO: allow data-clear of ANY app? 9851 if (MORE_DEBUG) Slog.v(TAG, "Privileged caller, allowing clear of other apps"); 9852 apps = new HashSet<String>(); 9853 int N = mBackupParticipants.size(); 9854 for (int i = 0; i < N; i++) { 9855 HashSet<String> s = mBackupParticipants.valueAt(i); 9856 if (s != null) { 9857 apps.addAll(s); 9858 } 9859 } 9860 } 9861 9862 // Is the given app an available participant? 9863 if (apps.contains(packageName)) { 9864 // found it; fire off the clear request 9865 if (MORE_DEBUG) Slog.v(TAG, "Found the app - running clear process"); 9866 mBackupHandler.removeMessages(MSG_RETRY_CLEAR); 9867 synchronized (mQueueLock) { 9868 final IBackupTransport transport = 9869 mTransportManager.getTransportBinder(transportName); 9870 if (transport == null) { 9871 // transport is currently unavailable -- make sure to retry 9872 Message msg = mBackupHandler.obtainMessage(MSG_RETRY_CLEAR, 9873 new ClearRetryParams(transportName, packageName)); 9874 mBackupHandler.sendMessageDelayed(msg, TRANSPORT_RETRY_INTERVAL); 9875 return; 9876 } 9877 long oldId = Binder.clearCallingIdentity(); 9878 mWakelock.acquire(); 9879 Message msg = mBackupHandler.obtainMessage(MSG_RUN_CLEAR, 9880 new ClearParams(transport, info)); 9881 mBackupHandler.sendMessage(msg); 9882 Binder.restoreCallingIdentity(oldId); 9883 } 9884 } 9885 } 9886 9887 // Run a backup pass immediately for any applications that have declared 9888 // that they have pending updates. 9889 public void backupNow() { 9890 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "backupNow"); 9891 9892 if (mPowerManager.isPowerSaveMode()) { 9893 if (DEBUG) Slog.v(TAG, "Not running backup while in battery save mode"); 9894 KeyValueBackupJob.schedule(mContext); // try again in several hours 9895 } else { 9896 if (DEBUG) Slog.v(TAG, "Scheduling immediate backup pass"); 9897 synchronized (mQueueLock) { 9898 // Fire the intent that kicks off the whole shebang... 9899 try { 9900 mRunBackupIntent.send(); 9901 } catch (PendingIntent.CanceledException e) { 9902 // should never happen 9903 Slog.e(TAG, "run-backup intent cancelled!"); 9904 } 9905 9906 // ...and cancel any pending scheduled job, because we've just superseded it 9907 KeyValueBackupJob.cancel(mContext); 9908 } 9909 } 9910 } 9911 9912 boolean deviceIsProvisioned() { 9913 final ContentResolver resolver = mContext.getContentResolver(); 9914 return (Settings.Global.getInt(resolver, Settings.Global.DEVICE_PROVISIONED, 0) != 0); 9915 } 9916 9917 // Run a *full* backup pass for the given packages, writing the resulting data stream 9918 // to the supplied file descriptor. This method is synchronous and does not return 9919 // to the caller until the backup has been completed. 9920 // 9921 // This is the variant used by 'adb backup'; it requires on-screen confirmation 9922 // by the user because it can be used to offload data over untrusted USB. 9923 public void fullBackup(ParcelFileDescriptor fd, boolean includeApks, 9924 boolean includeObbs, boolean includeShared, boolean doWidgets, 9925 boolean doAllApps, boolean includeSystem, boolean compress, String[] pkgList) { 9926 mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "fullBackup"); 9927 9928 final int callingUserHandle = UserHandle.getCallingUserId(); 9929 // TODO: http://b/22388012 9930 if (callingUserHandle != UserHandle.USER_SYSTEM) { 9931 throw new IllegalStateException("Backup supported only for the device owner"); 9932 } 9933 9934 // Validate 9935 if (!doAllApps) { 9936 if (!includeShared) { 9937 // If we're backing up shared data (sdcard or equivalent), then we can run 9938 // without any supplied app names. Otherwise, we'd be doing no work, so 9939 // report the error. 9940 if (pkgList == null || pkgList.length == 0) { 9941 throw new IllegalArgumentException( 9942 "Backup requested but neither shared nor any apps named"); 9943 } 9944 } 9945 } 9946 9947 long oldId = Binder.clearCallingIdentity(); 9948 try { 9949 // Doesn't make sense to do a full backup prior to setup 9950 if (!deviceIsProvisioned()) { 9951 Slog.i(TAG, "Full backup not supported before setup"); 9952 return; 9953 } 9954 9955 if (DEBUG) Slog.v(TAG, "Requesting full backup: apks=" + includeApks 9956 + " obb=" + includeObbs + " shared=" + includeShared + " all=" + doAllApps 9957 + " system=" + includeSystem + " pkgs=" + pkgList); 9958 Slog.i(TAG, "Beginning full backup..."); 9959 9960 FullBackupParams params = new FullBackupParams(fd, includeApks, includeObbs, 9961 includeShared, doWidgets, doAllApps, includeSystem, compress, pkgList); 9962 final int token = generateToken(); 9963 synchronized (mFullConfirmations) { 9964 mFullConfirmations.put(token, params); 9965 } 9966 9967 // start up the confirmation UI 9968 if (DEBUG) Slog.d(TAG, "Starting backup confirmation UI, token=" + token); 9969 if (!startConfirmationUi(token, FullBackup.FULL_BACKUP_INTENT_ACTION)) { 9970 Slog.e(TAG, "Unable to launch full backup confirmation"); 9971 mFullConfirmations.delete(token); 9972 return; 9973 } 9974 9975 // make sure the screen is lit for the user interaction 9976 mPowerManager.userActivity(SystemClock.uptimeMillis(), 9977 PowerManager.USER_ACTIVITY_EVENT_OTHER, 9978 0); 9979 9980 // start the confirmation countdown 9981 startConfirmationTimeout(token, params); 9982 9983 // wait for the backup to be performed 9984 if (DEBUG) Slog.d(TAG, "Waiting for full backup completion..."); 9985 waitForCompletion(params); 9986 } finally { 9987 try { 9988 fd.close(); 9989 } catch (IOException e) { 9990 // just eat it 9991 } 9992 Binder.restoreCallingIdentity(oldId); 9993 Slog.d(TAG, "Full backup processing complete."); 9994 } 9995 } 9996 9997 public void fullTransportBackup(String[] pkgNames) { 9998 mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, 9999 "fullTransportBackup"); 10000 10001 final int callingUserHandle = UserHandle.getCallingUserId(); 10002 // TODO: http://b/22388012 10003 if (callingUserHandle != UserHandle.USER_SYSTEM) { 10004 throw new IllegalStateException("Restore supported only for the device owner"); 10005 } 10006 10007 if (!fullBackupAllowable(mTransportManager.getCurrentTransportBinder())) { 10008 Slog.i(TAG, "Full backup not currently possible -- key/value backup not yet run?"); 10009 } else { 10010 if (DEBUG) { 10011 Slog.d(TAG, "fullTransportBackup()"); 10012 } 10013 10014 final long oldId = Binder.clearCallingIdentity(); 10015 try { 10016 CountDownLatch latch = new CountDownLatch(1); 10017 PerformFullTransportBackupTask task = new PerformFullTransportBackupTask(null, 10018 pkgNames, false, null, latch, null, null, false /* userInitiated */); 10019 // Acquiring wakelock for PerformFullTransportBackupTask before its start. 10020 mWakelock.acquire(); 10021 (new Thread(task, "full-transport-master")).start(); 10022 do { 10023 try { 10024 latch.await(); 10025 break; 10026 } catch (InterruptedException e) { 10027 // Just go back to waiting for the latch to indicate completion 10028 } 10029 } while (true); 10030 10031 // We just ran a backup on these packages, so kick them to the end of the queue 10032 final long now = System.currentTimeMillis(); 10033 for (String pkg : pkgNames) { 10034 enqueueFullBackup(pkg, now); 10035 } 10036 } finally { 10037 Binder.restoreCallingIdentity(oldId); 10038 } 10039 } 10040 10041 if (DEBUG) { 10042 Slog.d(TAG, "Done with full transport backup."); 10043 } 10044 } 10045 10046 public void fullRestore(ParcelFileDescriptor fd) { 10047 mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "fullRestore"); 10048 10049 final int callingUserHandle = UserHandle.getCallingUserId(); 10050 // TODO: http://b/22388012 10051 if (callingUserHandle != UserHandle.USER_SYSTEM) { 10052 throw new IllegalStateException("Restore supported only for the device owner"); 10053 } 10054 10055 long oldId = Binder.clearCallingIdentity(); 10056 10057 try { 10058 // Check whether the device has been provisioned -- we don't handle 10059 // full restores prior to completing the setup process. 10060 if (!deviceIsProvisioned()) { 10061 Slog.i(TAG, "Full restore not permitted before setup"); 10062 return; 10063 } 10064 10065 Slog.i(TAG, "Beginning full restore..."); 10066 10067 FullRestoreParams params = new FullRestoreParams(fd); 10068 final int token = generateToken(); 10069 synchronized (mFullConfirmations) { 10070 mFullConfirmations.put(token, params); 10071 } 10072 10073 // start up the confirmation UI 10074 if (DEBUG) Slog.d(TAG, "Starting restore confirmation UI, token=" + token); 10075 if (!startConfirmationUi(token, FullBackup.FULL_RESTORE_INTENT_ACTION)) { 10076 Slog.e(TAG, "Unable to launch full restore confirmation"); 10077 mFullConfirmations.delete(token); 10078 return; 10079 } 10080 10081 // make sure the screen is lit for the user interaction 10082 mPowerManager.userActivity(SystemClock.uptimeMillis(), 10083 PowerManager.USER_ACTIVITY_EVENT_OTHER, 10084 0); 10085 10086 // start the confirmation countdown 10087 startConfirmationTimeout(token, params); 10088 10089 // wait for the restore to be performed 10090 if (DEBUG) Slog.d(TAG, "Waiting for full restore completion..."); 10091 waitForCompletion(params); 10092 } finally { 10093 try { 10094 fd.close(); 10095 } catch (IOException e) { 10096 Slog.w(TAG, "Error trying to close fd after full restore: " + e); 10097 } 10098 Binder.restoreCallingIdentity(oldId); 10099 Slog.i(TAG, "Full restore processing complete."); 10100 } 10101 } 10102 10103 boolean startConfirmationUi(int token, String action) { 10104 try { 10105 Intent confIntent = new Intent(action); 10106 confIntent.setClassName("com.android.backupconfirm", 10107 "com.android.backupconfirm.BackupRestoreConfirmation"); 10108 confIntent.putExtra(FullBackup.CONF_TOKEN_INTENT_EXTRA, token); 10109 confIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 10110 mContext.startActivityAsUser(confIntent, UserHandle.SYSTEM); 10111 } catch (ActivityNotFoundException e) { 10112 return false; 10113 } 10114 return true; 10115 } 10116 10117 void startConfirmationTimeout(int token, FullParams params) { 10118 if (MORE_DEBUG) Slog.d(TAG, "Posting conf timeout msg after " 10119 + TIMEOUT_FULL_CONFIRMATION + " millis"); 10120 Message msg = mBackupHandler.obtainMessage(MSG_FULL_CONFIRMATION_TIMEOUT, 10121 token, 0, params); 10122 mBackupHandler.sendMessageDelayed(msg, TIMEOUT_FULL_CONFIRMATION); 10123 } 10124 10125 void waitForCompletion(FullParams params) { 10126 synchronized (params.latch) { 10127 while (params.latch.get() == false) { 10128 try { 10129 params.latch.wait(); 10130 } catch (InterruptedException e) { /* never interrupted */ } 10131 } 10132 } 10133 } 10134 10135 void signalFullBackupRestoreCompletion(FullParams params) { 10136 synchronized (params.latch) { 10137 params.latch.set(true); 10138 params.latch.notifyAll(); 10139 } 10140 } 10141 10142 // Confirm that the previously-requested full backup/restore operation can proceed. This 10143 // is used to require a user-facing disclosure about the operation. 10144 public void acknowledgeFullBackupOrRestore(int token, boolean allow, 10145 String curPassword, String encPpassword, IFullBackupRestoreObserver observer) { 10146 if (DEBUG) Slog.d(TAG, "acknowledgeFullBackupOrRestore : token=" + token 10147 + " allow=" + allow); 10148 10149 // TODO: possibly require not just this signature-only permission, but even 10150 // require that the specific designated confirmation-UI app uid is the caller? 10151 mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "acknowledgeFullBackupOrRestore"); 10152 10153 long oldId = Binder.clearCallingIdentity(); 10154 try { 10155 10156 FullParams params; 10157 synchronized (mFullConfirmations) { 10158 params = mFullConfirmations.get(token); 10159 if (params != null) { 10160 mBackupHandler.removeMessages(MSG_FULL_CONFIRMATION_TIMEOUT, params); 10161 mFullConfirmations.delete(token); 10162 10163 if (allow) { 10164 final int verb = params instanceof FullBackupParams 10165 ? MSG_RUN_ADB_BACKUP 10166 : MSG_RUN_ADB_RESTORE; 10167 10168 params.observer = observer; 10169 params.curPassword = curPassword; 10170 10171 params.encryptPassword = encPpassword; 10172 10173 if (MORE_DEBUG) Slog.d(TAG, "Sending conf message with verb " + verb); 10174 mWakelock.acquire(); 10175 Message msg = mBackupHandler.obtainMessage(verb, params); 10176 mBackupHandler.sendMessage(msg); 10177 } else { 10178 Slog.w(TAG, "User rejected full backup/restore operation"); 10179 // indicate completion without having actually transferred any data 10180 signalFullBackupRestoreCompletion(params); 10181 } 10182 } else { 10183 Slog.w(TAG, "Attempted to ack full backup/restore with invalid token"); 10184 } 10185 } 10186 } finally { 10187 Binder.restoreCallingIdentity(oldId); 10188 } 10189 } 10190 10191 private static boolean backupSettingMigrated(int userId) { 10192 File base = new File(Environment.getDataDirectory(), "backup"); 10193 File enableFile = new File(base, BACKUP_ENABLE_FILE); 10194 return enableFile.exists(); 10195 } 10196 10197 private static boolean readBackupEnableState(int userId) { 10198 File base = new File(Environment.getDataDirectory(), "backup"); 10199 File enableFile = new File(base, BACKUP_ENABLE_FILE); 10200 if (enableFile.exists()) { 10201 try (FileInputStream fin = new FileInputStream(enableFile)) { 10202 int state = fin.read(); 10203 return state != 0; 10204 } catch (IOException e) { 10205 // can't read the file; fall through to assume disabled 10206 Slog.e(TAG, "Cannot read enable state; assuming disabled"); 10207 } 10208 } else { 10209 if (DEBUG) { 10210 Slog.i(TAG, "isBackupEnabled() => false due to absent settings file"); 10211 } 10212 } 10213 return false; 10214 } 10215 10216 private static void writeBackupEnableState(boolean enable, int userId) { 10217 File base = new File(Environment.getDataDirectory(), "backup"); 10218 File enableFile = new File(base, BACKUP_ENABLE_FILE); 10219 File stage = new File(base, BACKUP_ENABLE_FILE + "-stage"); 10220 FileOutputStream fout = null; 10221 try { 10222 fout = new FileOutputStream(stage); 10223 fout.write(enable ? 1 : 0); 10224 fout.close(); 10225 stage.renameTo(enableFile); 10226 // will be synced immediately by the try-with-resources call to close() 10227 } catch (IOException|RuntimeException e) { 10228 // Whoops; looks like we're doomed. Roll everything out, disabled, 10229 // including the legacy state. 10230 Slog.e(TAG, "Unable to record backup enable state; reverting to disabled: " 10231 + e.getMessage()); 10232 10233 final ContentResolver r = sInstance.mContext.getContentResolver(); 10234 Settings.Secure.putStringForUser(r, 10235 Settings.Secure.BACKUP_ENABLED, null, userId); 10236 enableFile.delete(); 10237 stage.delete(); 10238 } finally { 10239 IoUtils.closeQuietly(fout); 10240 } 10241 } 10242 10243 // Enable/disable backups 10244 public void setBackupEnabled(boolean enable) { 10245 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, 10246 "setBackupEnabled"); 10247 10248 Slog.i(TAG, "Backup enabled => " + enable); 10249 10250 long oldId = Binder.clearCallingIdentity(); 10251 try { 10252 boolean wasEnabled = mEnabled; 10253 synchronized (this) { 10254 writeBackupEnableState(enable, UserHandle.USER_SYSTEM); 10255 mEnabled = enable; 10256 } 10257 10258 synchronized (mQueueLock) { 10259 if (enable && !wasEnabled && mProvisioned) { 10260 // if we've just been enabled, start scheduling backup passes 10261 KeyValueBackupJob.schedule(mContext); 10262 scheduleNextFullBackupJob(0); 10263 } else if (!enable) { 10264 // No longer enabled, so stop running backups 10265 if (MORE_DEBUG) Slog.i(TAG, "Opting out of backup"); 10266 10267 KeyValueBackupJob.cancel(mContext); 10268 10269 // This also constitutes an opt-out, so we wipe any data for 10270 // this device from the backend. We start that process with 10271 // an alarm in order to guarantee wakelock states. 10272 if (wasEnabled && mProvisioned) { 10273 // NOTE: we currently flush every registered transport, not just 10274 // the currently-active one. 10275 String[] allTransports = mTransportManager.getBoundTransportNames(); 10276 // build the set of transports for which we are posting an init 10277 for (String transport : allTransports) { 10278 recordInitPendingLocked(true, transport); 10279 } 10280 mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 10281 mRunInitIntent); 10282 } 10283 } 10284 } 10285 } finally { 10286 Binder.restoreCallingIdentity(oldId); 10287 } 10288 } 10289 10290 // Enable/disable automatic restore of app data at install time 10291 public void setAutoRestore(boolean doAutoRestore) { 10292 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, 10293 "setAutoRestore"); 10294 10295 Slog.i(TAG, "Auto restore => " + doAutoRestore); 10296 10297 final long oldId = Binder.clearCallingIdentity(); 10298 try { 10299 synchronized (this) { 10300 Settings.Secure.putInt(mContext.getContentResolver(), 10301 Settings.Secure.BACKUP_AUTO_RESTORE, doAutoRestore ? 1 : 0); 10302 mAutoRestore = doAutoRestore; 10303 } 10304 } finally { 10305 Binder.restoreCallingIdentity(oldId); 10306 } 10307 } 10308 10309 // Mark the backup service as having been provisioned 10310 public void setBackupProvisioned(boolean available) { 10311 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, 10312 "setBackupProvisioned"); 10313 /* 10314 * This is now a no-op; provisioning is simply the device's own setup state. 10315 */ 10316 } 10317 10318 // Report whether the backup mechanism is currently enabled 10319 public boolean isBackupEnabled() { 10320 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "isBackupEnabled"); 10321 return mEnabled; // no need to synchronize just to read it 10322 } 10323 10324 // Report the name of the currently active transport 10325 public String getCurrentTransport() { 10326 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, 10327 "getCurrentTransport"); 10328 String currentTransport = mTransportManager.getCurrentTransportName(); 10329 if (MORE_DEBUG) Slog.v(TAG, "... getCurrentTransport() returning " + currentTransport); 10330 return currentTransport; 10331 } 10332 10333 // Report all known, available backup transports 10334 public String[] listAllTransports() { 10335 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "listAllTransports"); 10336 10337 return mTransportManager.getBoundTransportNames(); 10338 } 10339 10340 public ComponentName[] listAllTransportComponents() { 10341 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, 10342 "listAllTransportComponents"); 10343 return mTransportManager.getAllTransportCompenents(); 10344 } 10345 10346 public String[] getTransportWhitelist() { 10347 // No permission check, intentionally. 10348 Set<ComponentName> whitelistedComponents = mTransportManager.getTransportWhitelist(); 10349 String[] whitelistedTransports = new String[whitelistedComponents.size()]; 10350 int i = 0; 10351 for (ComponentName component : whitelistedComponents) { 10352 whitelistedTransports[i] = component.flattenToShortString(); 10353 i++; 10354 } 10355 return whitelistedTransports; 10356 } 10357 10358 // Select which transport to use for the next backup operation. 10359 public String selectBackupTransport(String transport) { 10360 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, 10361 "selectBackupTransport"); 10362 10363 final long oldId = Binder.clearCallingIdentity(); 10364 try { 10365 String prevTransport = mTransportManager.selectTransport(transport); 10366 Settings.Secure.putString(mContext.getContentResolver(), 10367 Settings.Secure.BACKUP_TRANSPORT, transport); 10368 Slog.v(TAG, "selectBackupTransport() set " + mTransportManager.getCurrentTransportName() 10369 + " returning " + prevTransport); 10370 return prevTransport; 10371 } finally { 10372 Binder.restoreCallingIdentity(oldId); 10373 } 10374 } 10375 10376 public void selectBackupTransportAsync(final ComponentName transport, 10377 final ISelectBackupTransportCallback listener) { 10378 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, 10379 "selectBackupTransportAsync"); 10380 10381 final long oldId = Binder.clearCallingIdentity(); 10382 10383 Slog.v(TAG, "selectBackupTransportAsync() called with transport " + 10384 transport.flattenToShortString()); 10385 10386 mTransportManager.ensureTransportReady(transport, new SelectBackupTransportCallback() { 10387 @Override 10388 public void onSuccess(String transportName) { 10389 mTransportManager.selectTransport(transportName); 10390 Settings.Secure.putString(mContext.getContentResolver(), 10391 Settings.Secure.BACKUP_TRANSPORT, 10392 mTransportManager.getCurrentTransportName()); 10393 Slog.v(TAG, "Transport successfully selected: " + transport.flattenToShortString()); 10394 try { 10395 listener.onSuccess(transportName); 10396 } catch (RemoteException e) { 10397 // Nothing to do here. 10398 } 10399 } 10400 10401 @Override 10402 public void onFailure(int reason) { 10403 Slog.v(TAG, "Failed to select transport: " + transport.flattenToShortString()); 10404 try { 10405 listener.onFailure(reason); 10406 } catch (RemoteException e) { 10407 // Nothing to do here. 10408 } 10409 } 10410 }); 10411 10412 Binder.restoreCallingIdentity(oldId); 10413 } 10414 10415 // Supply the configuration Intent for the given transport. If the name is not one 10416 // of the available transports, or if the transport does not supply any configuration 10417 // UI, the method returns null. 10418 public Intent getConfigurationIntent(String transportName) { 10419 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, 10420 "getConfigurationIntent"); 10421 10422 final IBackupTransport transport = mTransportManager.getTransportBinder(transportName); 10423 if (transport != null) { 10424 try { 10425 final Intent intent = transport.configurationIntent(); 10426 if (MORE_DEBUG) Slog.d(TAG, "getConfigurationIntent() returning config intent " 10427 + intent); 10428 return intent; 10429 } catch (Exception e) { 10430 /* fall through to return null */ 10431 Slog.e(TAG, "Unable to get configuration intent from transport: " + e.getMessage()); 10432 } 10433 } 10434 10435 return null; 10436 } 10437 10438 // Supply the configuration summary string for the given transport. If the name is 10439 // not one of the available transports, or if the transport does not supply any 10440 // summary / destination string, the method can return null. 10441 // 10442 // This string is used VERBATIM as the summary text of the relevant Settings item! 10443 public String getDestinationString(String transportName) { 10444 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, 10445 "getDestinationString"); 10446 10447 final IBackupTransport transport = mTransportManager.getTransportBinder(transportName); 10448 if (transport != null) { 10449 try { 10450 final String text = transport.currentDestinationString(); 10451 if (MORE_DEBUG) Slog.d(TAG, "getDestinationString() returning " + text); 10452 return text; 10453 } catch (Exception e) { 10454 /* fall through to return null */ 10455 Slog.e(TAG, "Unable to get string from transport: " + e.getMessage()); 10456 } 10457 } 10458 10459 return null; 10460 } 10461 10462 // Supply the manage-data intent for the given transport. 10463 public Intent getDataManagementIntent(String transportName) { 10464 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, 10465 "getDataManagementIntent"); 10466 10467 final IBackupTransport transport = mTransportManager.getTransportBinder(transportName); 10468 if (transport != null) { 10469 try { 10470 final Intent intent = transport.dataManagementIntent(); 10471 if (MORE_DEBUG) Slog.d(TAG, "getDataManagementIntent() returning intent " 10472 + intent); 10473 return intent; 10474 } catch (Exception e) { 10475 /* fall through to return null */ 10476 Slog.e(TAG, "Unable to get management intent from transport: " + e.getMessage()); 10477 } 10478 } 10479 10480 return null; 10481 } 10482 10483 // Supply the menu label for affordances that fire the manage-data intent 10484 // for the given transport. 10485 public String getDataManagementLabel(String transportName) { 10486 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, 10487 "getDataManagementLabel"); 10488 10489 final IBackupTransport transport = mTransportManager.getTransportBinder(transportName); 10490 if (transport != null) { 10491 try { 10492 final String text = transport.dataManagementLabel(); 10493 if (MORE_DEBUG) Slog.d(TAG, "getDataManagementLabel() returning " + text); 10494 return text; 10495 } catch (Exception e) { 10496 /* fall through to return null */ 10497 Slog.e(TAG, "Unable to get management label from transport: " + e.getMessage()); 10498 } 10499 } 10500 10501 return null; 10502 } 10503 10504 // Callback: a requested backup agent has been instantiated. This should only 10505 // be called from the Activity Manager. 10506 public void agentConnected(String packageName, IBinder agentBinder) { 10507 synchronized(mAgentConnectLock) { 10508 if (Binder.getCallingUid() == Process.SYSTEM_UID) { 10509 Slog.d(TAG, "agentConnected pkg=" + packageName + " agent=" + agentBinder); 10510 IBackupAgent agent = IBackupAgent.Stub.asInterface(agentBinder); 10511 mConnectedAgent = agent; 10512 mConnecting = false; 10513 } else { 10514 Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid() 10515 + " claiming agent connected"); 10516 } 10517 mAgentConnectLock.notifyAll(); 10518 } 10519 } 10520 10521 // Callback: a backup agent has failed to come up, or has unexpectedly quit. 10522 // If the agent failed to come up in the first place, the agentBinder argument 10523 // will be null. This should only be called from the Activity Manager. 10524 public void agentDisconnected(String packageName) { 10525 // TODO: handle backup being interrupted 10526 synchronized(mAgentConnectLock) { 10527 if (Binder.getCallingUid() == Process.SYSTEM_UID) { 10528 mConnectedAgent = null; 10529 mConnecting = false; 10530 } else { 10531 Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid() 10532 + " claiming agent disconnected"); 10533 } 10534 mAgentConnectLock.notifyAll(); 10535 } 10536 } 10537 10538 // An application being installed will need a restore pass, then the Package Manager 10539 // will need to be told when the restore is finished. 10540 public void restoreAtInstall(String packageName, int token) { 10541 if (Binder.getCallingUid() != Process.SYSTEM_UID) { 10542 Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid() 10543 + " attemping install-time restore"); 10544 return; 10545 } 10546 10547 boolean skip = false; 10548 10549 long restoreSet = getAvailableRestoreToken(packageName); 10550 if (DEBUG) Slog.v(TAG, "restoreAtInstall pkg=" + packageName 10551 + " token=" + Integer.toHexString(token) 10552 + " restoreSet=" + Long.toHexString(restoreSet)); 10553 if (restoreSet == 0) { 10554 if (MORE_DEBUG) Slog.i(TAG, "No restore set"); 10555 skip = true; 10556 } 10557 10558 // Do we have a transport to fetch data for us? 10559 IBackupTransport transport = mTransportManager.getCurrentTransportBinder(); 10560 if (transport == null) { 10561 if (DEBUG) Slog.w(TAG, "No transport"); 10562 skip = true; 10563 } 10564 10565 if (!mAutoRestore) { 10566 if (DEBUG) { 10567 Slog.w(TAG, "Non-restorable state: auto=" + mAutoRestore); 10568 } 10569 skip = true; 10570 } 10571 10572 if (!skip) { 10573 try { 10574 // okay, we're going to attempt a restore of this package from this restore set. 10575 // The eventual message back into the Package Manager to run the post-install 10576 // steps for 'token' will be issued from the restore handling code. 10577 10578 // This can throw and so *must* happen before the wakelock is acquired 10579 String dirName = transport.transportDirName(); 10580 10581 mWakelock.acquire(); 10582 if (MORE_DEBUG) { 10583 Slog.d(TAG, "Restore at install of " + packageName); 10584 } 10585 Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE); 10586 msg.obj = new RestoreParams(transport, dirName, null, null, 10587 restoreSet, packageName, token); 10588 mBackupHandler.sendMessage(msg); 10589 } catch (Exception e) { 10590 // Calling into the transport broke; back off and proceed with the installation. 10591 Slog.e(TAG, "Unable to contact transport: " + e.getMessage()); 10592 skip = true; 10593 } 10594 } 10595 10596 if (skip) { 10597 // Auto-restore disabled or no way to attempt a restore; just tell the Package 10598 // Manager to proceed with the post-install handling for this package. 10599 if (DEBUG) Slog.v(TAG, "Finishing install immediately"); 10600 try { 10601 mPackageManagerBinder.finishPackageInstall(token, false); 10602 } catch (RemoteException e) { /* can't happen */ } 10603 } 10604 } 10605 10606 // Hand off a restore session 10607 public IRestoreSession beginRestoreSession(String packageName, String transport) { 10608 if (DEBUG) Slog.v(TAG, "beginRestoreSession: pkg=" + packageName 10609 + " transport=" + transport); 10610 10611 boolean needPermission = true; 10612 if (transport == null) { 10613 transport = mTransportManager.getCurrentTransportName(); 10614 10615 if (packageName != null) { 10616 PackageInfo app = null; 10617 try { 10618 app = mPackageManager.getPackageInfo(packageName, 0); 10619 } catch (NameNotFoundException nnf) { 10620 Slog.w(TAG, "Asked to restore nonexistent pkg " + packageName); 10621 throw new IllegalArgumentException("Package " + packageName + " not found"); 10622 } 10623 10624 if (app.applicationInfo.uid == Binder.getCallingUid()) { 10625 // So: using the current active transport, and the caller has asked 10626 // that its own package will be restored. In this narrow use case 10627 // we do not require the caller to hold the permission. 10628 needPermission = false; 10629 } 10630 } 10631 } 10632 10633 if (needPermission) { 10634 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, 10635 "beginRestoreSession"); 10636 } else { 10637 if (DEBUG) Slog.d(TAG, "restoring self on current transport; no permission needed"); 10638 } 10639 10640 synchronized(this) { 10641 if (mActiveRestoreSession != null) { 10642 Slog.i(TAG, "Restore session requested but one already active"); 10643 return null; 10644 } 10645 if (mBackupRunning) { 10646 Slog.i(TAG, "Restore session requested but currently running backups"); 10647 return null; 10648 } 10649 mActiveRestoreSession = new ActiveRestoreSession(packageName, transport); 10650 mBackupHandler.sendEmptyMessageDelayed(MSG_RESTORE_SESSION_TIMEOUT, 10651 TIMEOUT_RESTORE_INTERVAL); 10652 } 10653 return mActiveRestoreSession; 10654 } 10655 10656 void clearRestoreSession(ActiveRestoreSession currentSession) { 10657 synchronized(this) { 10658 if (currentSession != mActiveRestoreSession) { 10659 Slog.e(TAG, "ending non-current restore session"); 10660 } else { 10661 if (DEBUG) Slog.v(TAG, "Clearing restore session and halting timeout"); 10662 mActiveRestoreSession = null; 10663 mBackupHandler.removeMessages(MSG_RESTORE_SESSION_TIMEOUT); 10664 } 10665 } 10666 } 10667 10668 // Note that a currently-active backup agent has notified us that it has 10669 // completed the given outstanding asynchronous backup/restore operation. 10670 public void opComplete(int token, long result) { 10671 if (MORE_DEBUG) { 10672 Slog.v(TAG, "opComplete: " + Integer.toHexString(token) + " result=" + result); 10673 } 10674 Operation op = null; 10675 synchronized (mCurrentOpLock) { 10676 op = mCurrentOperations.get(token); 10677 if (op != null) { 10678 if (op.state == OP_TIMEOUT) { 10679 // The operation already timed out, and this is a late response. Tidy up 10680 // and ignore it; we've already dealt with the timeout. 10681 op = null; 10682 mCurrentOperations.delete(token); 10683 } else if (op.state == OP_ACKNOWLEDGED) { 10684 if (DEBUG) { 10685 Slog.w(TAG, "Received duplicate ack for token=" + 10686 Integer.toHexString(token)); 10687 } 10688 op = null; 10689 mCurrentOperations.remove(token); 10690 } else if (op.state == OP_PENDING) { 10691 // Can't delete op from mCurrentOperations. waitUntilOperationComplete can be 10692 // called after we we receive this call. 10693 op.state = OP_ACKNOWLEDGED; 10694 } 10695 } 10696 mCurrentOpLock.notifyAll(); 10697 } 10698 10699 // The completion callback, if any, is invoked on the handler 10700 if (op != null && op.callback != null) { 10701 Pair<BackupRestoreTask, Long> callbackAndResult = Pair.create(op.callback, result); 10702 Message msg = mBackupHandler.obtainMessage(MSG_OP_COMPLETE, callbackAndResult); 10703 mBackupHandler.sendMessage(msg); 10704 } 10705 } 10706 10707 public boolean isAppEligibleForBackup(String packageName) { 10708 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, 10709 "isAppEligibleForBackup"); 10710 try { 10711 PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, 10712 PackageManager.GET_SIGNATURES); 10713 if (!appIsEligibleForBackup(packageInfo.applicationInfo) || 10714 appIsStopped(packageInfo.applicationInfo)) { 10715 return false; 10716 } 10717 IBackupTransport transport = mTransportManager.getCurrentTransportBinder(); 10718 if (transport != null) { 10719 try { 10720 return transport.isAppEligibleForBackup(packageInfo, 10721 appGetsFullBackup(packageInfo)); 10722 } catch (Exception e) { 10723 Slog.e(TAG, "Unable to ask about eligibility: " + e.getMessage()); 10724 } 10725 } 10726 // If transport is not present we couldn't tell that the package is not eligible. 10727 return true; 10728 } catch (NameNotFoundException e) { 10729 return false; 10730 } 10731 } 10732 10733 // ----- Restore session ----- 10734 10735 class ActiveRestoreSession extends IRestoreSession.Stub { 10736 private static final String TAG = "RestoreSession"; 10737 10738 private String mPackageName; 10739 private IBackupTransport mRestoreTransport = null; 10740 RestoreSet[] mRestoreSets = null; 10741 boolean mEnded = false; 10742 boolean mTimedOut = false; 10743 10744 ActiveRestoreSession(String packageName, String transport) { 10745 mPackageName = packageName; 10746 mRestoreTransport = mTransportManager.getTransportBinder(transport); 10747 } 10748 10749 public void markTimedOut() { 10750 mTimedOut = true; 10751 } 10752 10753 // --- Binder interface --- 10754 public synchronized int getAvailableRestoreSets(IRestoreObserver observer, 10755 IBackupManagerMonitor monitor) { 10756 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, 10757 "getAvailableRestoreSets"); 10758 if (observer == null) { 10759 throw new IllegalArgumentException("Observer must not be null"); 10760 } 10761 10762 if (mEnded) { 10763 throw new IllegalStateException("Restore session already ended"); 10764 } 10765 10766 if (mTimedOut) { 10767 Slog.i(TAG, "Session already timed out"); 10768 return -1; 10769 } 10770 10771 long oldId = Binder.clearCallingIdentity(); 10772 try { 10773 if (mRestoreTransport == null) { 10774 Slog.w(TAG, "Null transport getting restore sets"); 10775 return -1; 10776 } 10777 10778 // We know we're doing legit work now, so halt the timeout 10779 // until we're done. It gets started again when the result 10780 // comes in. 10781 mBackupHandler.removeMessages(MSG_RESTORE_SESSION_TIMEOUT); 10782 10783 // spin off the transport request to our service thread 10784 mWakelock.acquire(); 10785 Message msg = mBackupHandler.obtainMessage(MSG_RUN_GET_RESTORE_SETS, 10786 new RestoreGetSetsParams(mRestoreTransport, this, observer, 10787 monitor)); 10788 mBackupHandler.sendMessage(msg); 10789 return 0; 10790 } catch (Exception e) { 10791 Slog.e(TAG, "Error in getAvailableRestoreSets", e); 10792 return -1; 10793 } finally { 10794 Binder.restoreCallingIdentity(oldId); 10795 } 10796 } 10797 10798 public synchronized int restoreAll(long token, IRestoreObserver observer, 10799 IBackupManagerMonitor monitor) { 10800 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, 10801 "performRestore"); 10802 10803 if (DEBUG) Slog.d(TAG, "restoreAll token=" + Long.toHexString(token) 10804 + " observer=" + observer); 10805 10806 if (mEnded) { 10807 throw new IllegalStateException("Restore session already ended"); 10808 } 10809 10810 if (mTimedOut) { 10811 Slog.i(TAG, "Session already timed out"); 10812 return -1; 10813 } 10814 10815 if (mRestoreTransport == null || mRestoreSets == null) { 10816 Slog.e(TAG, "Ignoring restoreAll() with no restore set"); 10817 return -1; 10818 } 10819 10820 if (mPackageName != null) { 10821 Slog.e(TAG, "Ignoring restoreAll() on single-package session"); 10822 return -1; 10823 } 10824 10825 String dirName; 10826 try { 10827 dirName = mRestoreTransport.transportDirName(); 10828 } catch (Exception e) { 10829 // Transport went AWOL; fail. 10830 Slog.e(TAG, "Unable to get transport dir for restore: " + e.getMessage()); 10831 return -1; 10832 } 10833 10834 synchronized (mQueueLock) { 10835 for (int i = 0; i < mRestoreSets.length; i++) { 10836 if (token == mRestoreSets[i].token) { 10837 // Real work, so stop the session timeout until we finalize the restore 10838 mBackupHandler.removeMessages(MSG_RESTORE_SESSION_TIMEOUT); 10839 10840 long oldId = Binder.clearCallingIdentity(); 10841 mWakelock.acquire(); 10842 if (MORE_DEBUG) { 10843 Slog.d(TAG, "restoreAll() kicking off"); 10844 } 10845 Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE); 10846 msg.obj = new RestoreParams(mRestoreTransport, dirName, 10847 observer, monitor, token); 10848 mBackupHandler.sendMessage(msg); 10849 Binder.restoreCallingIdentity(oldId); 10850 return 0; 10851 } 10852 } 10853 } 10854 10855 Slog.w(TAG, "Restore token " + Long.toHexString(token) + " not found"); 10856 return -1; 10857 } 10858 10859 // Restores of more than a single package are treated as 'system' restores 10860 public synchronized int restoreSome(long token, IRestoreObserver observer, 10861 IBackupManagerMonitor monitor, String[] packages) { 10862 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, 10863 "performRestore"); 10864 10865 if (DEBUG) { 10866 StringBuilder b = new StringBuilder(128); 10867 b.append("restoreSome token="); 10868 b.append(Long.toHexString(token)); 10869 b.append(" observer="); 10870 b.append(observer.toString()); 10871 b.append(" monitor="); 10872 if (monitor == null) { 10873 b.append("null"); 10874 } else { 10875 b.append(monitor.toString()); 10876 } 10877 b.append(" packages="); 10878 if (packages == null) { 10879 b.append("null"); 10880 } else { 10881 b.append('{'); 10882 boolean first = true; 10883 for (String s : packages) { 10884 if (!first) { 10885 b.append(", "); 10886 } else first = false; 10887 b.append(s); 10888 } 10889 b.append('}'); 10890 } 10891 Slog.d(TAG, b.toString()); 10892 } 10893 10894 if (mEnded) { 10895 throw new IllegalStateException("Restore session already ended"); 10896 } 10897 10898 if (mTimedOut) { 10899 Slog.i(TAG, "Session already timed out"); 10900 return -1; 10901 } 10902 10903 if (mRestoreTransport == null || mRestoreSets == null) { 10904 Slog.e(TAG, "Ignoring restoreAll() with no restore set"); 10905 return -1; 10906 } 10907 10908 if (mPackageName != null) { 10909 Slog.e(TAG, "Ignoring restoreAll() on single-package session"); 10910 return -1; 10911 } 10912 10913 String dirName; 10914 try { 10915 dirName = mRestoreTransport.transportDirName(); 10916 } catch (Exception e) { 10917 // Transport went AWOL; fail. 10918 Slog.e(TAG, "Unable to get transport name for restoreSome: " + e.getMessage()); 10919 return -1; 10920 } 10921 10922 synchronized (mQueueLock) { 10923 for (int i = 0; i < mRestoreSets.length; i++) { 10924 if (token == mRestoreSets[i].token) { 10925 // Stop the session timeout until we finalize the restore 10926 mBackupHandler.removeMessages(MSG_RESTORE_SESSION_TIMEOUT); 10927 10928 long oldId = Binder.clearCallingIdentity(); 10929 mWakelock.acquire(); 10930 if (MORE_DEBUG) { 10931 Slog.d(TAG, "restoreSome() of " + packages.length + " packages"); 10932 } 10933 Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE); 10934 msg.obj = new RestoreParams(mRestoreTransport, dirName, observer, monitor, 10935 token, packages, packages.length > 1); 10936 mBackupHandler.sendMessage(msg); 10937 Binder.restoreCallingIdentity(oldId); 10938 return 0; 10939 } 10940 } 10941 } 10942 10943 Slog.w(TAG, "Restore token " + Long.toHexString(token) + " not found"); 10944 return -1; 10945 } 10946 10947 public synchronized int restorePackage(String packageName, IRestoreObserver observer, 10948 IBackupManagerMonitor monitor) { 10949 if (DEBUG) Slog.v(TAG, "restorePackage pkg=" + packageName + " obs=" + observer 10950 + "monitor=" + monitor); 10951 10952 if (mEnded) { 10953 throw new IllegalStateException("Restore session already ended"); 10954 } 10955 10956 if (mTimedOut) { 10957 Slog.i(TAG, "Session already timed out"); 10958 return -1; 10959 } 10960 10961 if (mPackageName != null) { 10962 if (! mPackageName.equals(packageName)) { 10963 Slog.e(TAG, "Ignoring attempt to restore pkg=" + packageName 10964 + " on session for package " + mPackageName); 10965 return -1; 10966 } 10967 } 10968 10969 PackageInfo app = null; 10970 try { 10971 app = mPackageManager.getPackageInfo(packageName, 0); 10972 } catch (NameNotFoundException nnf) { 10973 Slog.w(TAG, "Asked to restore nonexistent pkg " + packageName); 10974 return -1; 10975 } 10976 10977 // If the caller is not privileged and is not coming from the target 10978 // app's uid, throw a permission exception back to the caller. 10979 int perm = mContext.checkPermission(android.Manifest.permission.BACKUP, 10980 Binder.getCallingPid(), Binder.getCallingUid()); 10981 if ((perm == PackageManager.PERMISSION_DENIED) && 10982 (app.applicationInfo.uid != Binder.getCallingUid())) { 10983 Slog.w(TAG, "restorePackage: bad packageName=" + packageName 10984 + " or calling uid=" + Binder.getCallingUid()); 10985 throw new SecurityException("No permission to restore other packages"); 10986 } 10987 10988 // So far so good; we're allowed to try to restore this package. 10989 long oldId = Binder.clearCallingIdentity(); 10990 try { 10991 // Check whether there is data for it in the current dataset, falling back 10992 // to the ancestral dataset if not. 10993 long token = getAvailableRestoreToken(packageName); 10994 if (DEBUG) Slog.v(TAG, "restorePackage pkg=" + packageName 10995 + " token=" + Long.toHexString(token)); 10996 10997 // If we didn't come up with a place to look -- no ancestral dataset and 10998 // the app has never been backed up from this device -- there's nothing 10999 // to do but return failure. 11000 if (token == 0) { 11001 if (DEBUG) Slog.w(TAG, "No data available for this package; not restoring"); 11002 return -1; 11003 } 11004 11005 String dirName; 11006 try { 11007 dirName = mRestoreTransport.transportDirName(); 11008 } catch (Exception e) { 11009 // Transport went AWOL; fail. 11010 Slog.e(TAG, "Unable to get transport dir for restorePackage: " + e.getMessage()); 11011 return -1; 11012 } 11013 11014 // Stop the session timeout until we finalize the restore 11015 mBackupHandler.removeMessages(MSG_RESTORE_SESSION_TIMEOUT); 11016 11017 // Ready to go: enqueue the restore request and claim success 11018 mWakelock.acquire(); 11019 if (MORE_DEBUG) { 11020 Slog.d(TAG, "restorePackage() : " + packageName); 11021 } 11022 Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE); 11023 msg.obj = new RestoreParams(mRestoreTransport, dirName, observer, monitor, 11024 token, app); 11025 mBackupHandler.sendMessage(msg); 11026 } finally { 11027 Binder.restoreCallingIdentity(oldId); 11028 } 11029 return 0; 11030 } 11031 11032 // Posted to the handler to tear down a restore session in a cleanly synchronized way 11033 class EndRestoreRunnable implements Runnable { 11034 BackupManagerService mBackupManager; 11035 ActiveRestoreSession mSession; 11036 11037 EndRestoreRunnable(BackupManagerService manager, ActiveRestoreSession session) { 11038 mBackupManager = manager; 11039 mSession = session; 11040 } 11041 11042 public void run() { 11043 // clean up the session's bookkeeping 11044 synchronized (mSession) { 11045 mSession.mRestoreTransport = null; 11046 mSession.mEnded = true; 11047 } 11048 11049 // clean up the BackupManagerImpl side of the bookkeeping 11050 // and cancel any pending timeout message 11051 mBackupManager.clearRestoreSession(mSession); 11052 } 11053 } 11054 11055 public synchronized void endRestoreSession() { 11056 if (DEBUG) Slog.d(TAG, "endRestoreSession"); 11057 11058 if (mTimedOut) { 11059 Slog.i(TAG, "Session already timed out"); 11060 return; 11061 } 11062 11063 if (mEnded) { 11064 throw new IllegalStateException("Restore session already ended"); 11065 } 11066 11067 mBackupHandler.post(new EndRestoreRunnable(BackupManagerService.this, this)); 11068 } 11069 } 11070 11071 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 11072 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); 11073 11074 long identityToken = Binder.clearCallingIdentity(); 11075 try { 11076 if (args != null) { 11077 for (String arg : args) { 11078 if ("-h".equals(arg)) { 11079 pw.println("'dumpsys backup' optional arguments:"); 11080 pw.println(" -h : this help text"); 11081 pw.println(" a[gents] : dump information about defined backup agents"); 11082 return; 11083 } else if ("agents".startsWith(arg)) { 11084 dumpAgents(pw); 11085 return; 11086 } 11087 } 11088 } 11089 dumpInternal(pw); 11090 } finally { 11091 Binder.restoreCallingIdentity(identityToken); 11092 } 11093 } 11094 11095 private void dumpAgents(PrintWriter pw) { 11096 List<PackageInfo> agentPackages = allAgentPackages(); 11097 pw.println("Defined backup agents:"); 11098 for (PackageInfo pkg : agentPackages) { 11099 pw.print(" "); 11100 pw.print(pkg.packageName); pw.println(':'); 11101 pw.print(" "); pw.println(pkg.applicationInfo.backupAgentName); 11102 } 11103 } 11104 11105 private void dumpInternal(PrintWriter pw) { 11106 synchronized (mQueueLock) { 11107 pw.println("Backup Manager is " + (mEnabled ? "enabled" : "disabled") 11108 + " / " + (!mProvisioned ? "not " : "") + "provisioned / " 11109 + (this.mPendingInits.size() == 0 ? "not " : "") + "pending init"); 11110 pw.println("Auto-restore is " + (mAutoRestore ? "enabled" : "disabled")); 11111 if (mBackupRunning) pw.println("Backup currently running"); 11112 pw.println("Last backup pass started: " + mLastBackupPass 11113 + " (now = " + System.currentTimeMillis() + ')'); 11114 pw.println(" next scheduled: " + KeyValueBackupJob.nextScheduled()); 11115 11116 pw.println("Transport whitelist:"); 11117 for (ComponentName transport : mTransportManager.getTransportWhitelist()) { 11118 pw.print(" "); 11119 pw.println(transport.flattenToShortString()); 11120 } 11121 11122 pw.println("Available transports:"); 11123 final String[] transports = listAllTransports(); 11124 if (transports != null) { 11125 for (String t : listAllTransports()) { 11126 pw.println((t.equals(mTransportManager.getCurrentTransportName()) ? " * " : " ") + t); 11127 try { 11128 IBackupTransport transport = mTransportManager.getTransportBinder(t); 11129 File dir = new File(mBaseStateDir, transport.transportDirName()); 11130 pw.println(" destination: " + transport.currentDestinationString()); 11131 pw.println(" intent: " + transport.configurationIntent()); 11132 for (File f : dir.listFiles()) { 11133 pw.println(" " + f.getName() + " - " + f.length() + " state bytes"); 11134 } 11135 } catch (Exception e) { 11136 Slog.e(TAG, "Error in transport", e); 11137 pw.println(" Error: " + e); 11138 } 11139 } 11140 } 11141 11142 pw.println("Pending init: " + mPendingInits.size()); 11143 for (String s : mPendingInits) { 11144 pw.println(" " + s); 11145 } 11146 11147 if (DEBUG_BACKUP_TRACE) { 11148 synchronized (mBackupTrace) { 11149 if (!mBackupTrace.isEmpty()) { 11150 pw.println("Most recent backup trace:"); 11151 for (String s : mBackupTrace) { 11152 pw.println(" " + s); 11153 } 11154 } 11155 } 11156 } 11157 11158 pw.print("Ancestral: "); pw.println(Long.toHexString(mAncestralToken)); 11159 pw.print("Current: "); pw.println(Long.toHexString(mCurrentToken)); 11160 11161 int N = mBackupParticipants.size(); 11162 pw.println("Participants:"); 11163 for (int i=0; i<N; i++) { 11164 int uid = mBackupParticipants.keyAt(i); 11165 pw.print(" uid: "); 11166 pw.println(uid); 11167 HashSet<String> participants = mBackupParticipants.valueAt(i); 11168 for (String app: participants) { 11169 pw.println(" " + app); 11170 } 11171 } 11172 11173 pw.println("Ancestral packages: " 11174 + (mAncestralPackages == null ? "none" : mAncestralPackages.size())); 11175 if (mAncestralPackages != null) { 11176 for (String pkg : mAncestralPackages) { 11177 pw.println(" " + pkg); 11178 } 11179 } 11180 11181 pw.println("Ever backed up: " + mEverStoredApps.size()); 11182 for (String pkg : mEverStoredApps) { 11183 pw.println(" " + pkg); 11184 } 11185 11186 pw.println("Pending key/value backup: " + mPendingBackups.size()); 11187 for (BackupRequest req : mPendingBackups.values()) { 11188 pw.println(" " + req); 11189 } 11190 11191 pw.println("Full backup queue:" + mFullBackupQueue.size()); 11192 for (FullBackupEntry entry : mFullBackupQueue) { 11193 pw.print(" "); pw.print(entry.lastBackup); 11194 pw.print(" : "); pw.println(entry.packageName); 11195 } 11196 } 11197 } 11198 11199 private static void sendBackupOnUpdate(IBackupObserver observer, String packageName, 11200 BackupProgress progress) { 11201 if (observer != null) { 11202 try { 11203 observer.onUpdate(packageName, progress); 11204 } catch (RemoteException e) { 11205 if (DEBUG) { 11206 Slog.w(TAG, "Backup observer went away: onUpdate"); 11207 } 11208 } 11209 } 11210 } 11211 11212 private static void sendBackupOnPackageResult(IBackupObserver observer, String packageName, 11213 int status) { 11214 if (observer != null) { 11215 try { 11216 observer.onResult(packageName, status); 11217 } catch (RemoteException e) { 11218 if (DEBUG) { 11219 Slog.w(TAG, "Backup observer went away: onResult"); 11220 } 11221 } 11222 } 11223 } 11224 11225 private static void sendBackupFinished(IBackupObserver observer, int status) { 11226 if (observer != null) { 11227 try { 11228 observer.backupFinished(status); 11229 } catch (RemoteException e) { 11230 if (DEBUG) { 11231 Slog.w(TAG, "Backup observer went away: backupFinished"); 11232 } 11233 } 11234 } 11235 } 11236 11237 private Bundle putMonitoringExtra(Bundle extras, String key, String value) { 11238 if (extras == null) { 11239 extras = new Bundle(); 11240 } 11241 extras.putString(key, value); 11242 return extras; 11243 } 11244 11245 private Bundle putMonitoringExtra(Bundle extras, String key, int value) { 11246 if (extras == null) { 11247 extras = new Bundle(); 11248 } 11249 extras.putInt(key, value); 11250 return extras; 11251 } 11252 11253 private Bundle putMonitoringExtra(Bundle extras, String key, long value) { 11254 if (extras == null) { 11255 extras = new Bundle(); 11256 } 11257 extras.putLong(key, value); 11258 return extras; 11259 } 11260 11261 11262 private Bundle putMonitoringExtra(Bundle extras, String key, boolean value) { 11263 if (extras == null) { 11264 extras = new Bundle(); 11265 } 11266 extras.putBoolean(key, value); 11267 return extras; 11268 } 11269 11270 private static IBackupManagerMonitor monitorEvent(IBackupManagerMonitor monitor, int id, 11271 PackageInfo pkg, int category, Bundle extras) { 11272 if (monitor != null) { 11273 try { 11274 Bundle bundle = new Bundle(); 11275 bundle.putInt(BackupManagerMonitor.EXTRA_LOG_EVENT_ID, id); 11276 bundle.putInt(BackupManagerMonitor.EXTRA_LOG_EVENT_CATEGORY, category); 11277 if (pkg != null) { 11278 bundle.putString(EXTRA_LOG_EVENT_PACKAGE_NAME, 11279 pkg.packageName); 11280 bundle.putInt(BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_VERSION, 11281 pkg.versionCode); 11282 } 11283 if (extras != null) { 11284 bundle.putAll(extras); 11285 } 11286 monitor.onEvent(bundle); 11287 return monitor; 11288 } catch(RemoteException e) { 11289 if (DEBUG) { 11290 Slog.w(TAG, "backup manager monitor went away"); 11291 } 11292 } 11293 } 11294 return null; 11295 } 11296} 11297