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