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