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