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