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