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