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