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