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