PageRenderTime 112ms CodeModel.GetById 29ms app.highlight 60ms RepoModel.GetById 1ms app.codeStats 2ms

/services/java/com/android/server/BackupManagerService.java

https://github.com/aizuzi/platform_frameworks_base
Java | 6288 lines | 4725 code | 698 blank | 865 comment | 1000 complexity | 7a00f18c337f24c4bb4331b40a664d70 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   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;
  18
  19import android.app.ActivityManagerNative;
  20import android.app.AlarmManager;
  21import android.app.AppGlobals;
  22import android.app.IActivityManager;
  23import android.app.IApplicationThread;
  24import android.app.IBackupAgent;
  25import android.app.PendingIntent;
  26import android.app.backup.BackupAgent;
  27import android.app.backup.BackupDataOutput;
  28import android.app.backup.FullBackup;
  29import android.app.backup.RestoreSet;
  30import android.app.backup.IBackupManager;
  31import android.app.backup.IFullBackupRestoreObserver;
  32import android.app.backup.IRestoreObserver;
  33import android.app.backup.IRestoreSession;
  34import android.content.ActivityNotFoundException;
  35import android.content.BroadcastReceiver;
  36import android.content.ComponentName;
  37import android.content.ContentResolver;
  38import android.content.Context;
  39import android.content.Intent;
  40import android.content.IntentFilter;
  41import android.content.ServiceConnection;
  42import android.content.pm.ApplicationInfo;
  43import android.content.pm.IPackageDataObserver;
  44import android.content.pm.IPackageDeleteObserver;
  45import android.content.pm.IPackageInstallObserver;
  46import android.content.pm.IPackageManager;
  47import android.content.pm.PackageInfo;
  48import android.content.pm.PackageManager;
  49import android.content.pm.ResolveInfo;
  50import android.content.pm.ServiceInfo;
  51import android.content.pm.Signature;
  52import android.content.pm.PackageManager.NameNotFoundException;
  53import android.database.ContentObserver;
  54import android.net.Uri;
  55import android.os.Binder;
  56import android.os.Build;
  57import android.os.Bundle;
  58import android.os.Environment;
  59import android.os.Handler;
  60import android.os.HandlerThread;
  61import android.os.IBinder;
  62import android.os.Looper;
  63import android.os.Message;
  64import android.os.ParcelFileDescriptor;
  65import android.os.PowerManager;
  66import android.os.Process;
  67import android.os.RemoteException;
  68import android.os.SELinux;
  69import android.os.ServiceManager;
  70import android.os.SystemClock;
  71import android.os.UserHandle;
  72import android.os.WorkSource;
  73import android.os.Environment.UserEnvironment;
  74import android.os.storage.IMountService;
  75import android.provider.Settings;
  76import android.util.EventLog;
  77import android.util.Log;
  78import android.util.Slog;
  79import android.util.SparseArray;
  80import android.util.StringBuilderPrinter;
  81
  82import com.android.internal.backup.BackupConstants;
  83import com.android.internal.backup.IBackupTransport;
  84import com.android.internal.backup.IObbBackupService;
  85import com.android.server.EventLogTags;
  86import com.android.server.PackageManagerBackupAgent.Metadata;
  87
  88import java.io.BufferedInputStream;
  89import java.io.BufferedOutputStream;
  90import java.io.ByteArrayOutputStream;
  91import java.io.DataInputStream;
  92import java.io.DataOutputStream;
  93import java.io.EOFException;
  94import java.io.File;
  95import java.io.FileDescriptor;
  96import java.io.FileInputStream;
  97import java.io.FileNotFoundException;
  98import java.io.FileOutputStream;
  99import java.io.IOException;
 100import java.io.InputStream;
 101import java.io.OutputStream;
 102import java.io.PrintWriter;
 103import java.io.RandomAccessFile;
 104import java.security.InvalidAlgorithmParameterException;
 105import java.security.InvalidKeyException;
 106import java.security.Key;
 107import java.security.NoSuchAlgorithmException;
 108import java.security.SecureRandom;
 109import java.security.spec.InvalidKeySpecException;
 110import java.security.spec.KeySpec;
 111import java.text.SimpleDateFormat;
 112import java.util.ArrayList;
 113import java.util.Arrays;
 114import java.util.Date;
 115import java.util.HashMap;
 116import java.util.HashSet;
 117import java.util.List;
 118import java.util.Map;
 119import java.util.Random;
 120import java.util.Set;
 121import java.util.concurrent.atomic.AtomicBoolean;
 122import java.util.zip.Deflater;
 123import java.util.zip.DeflaterOutputStream;
 124import java.util.zip.InflaterInputStream;
 125
 126import javax.crypto.BadPaddingException;
 127import javax.crypto.Cipher;
 128import javax.crypto.CipherInputStream;
 129import javax.crypto.CipherOutputStream;
 130import javax.crypto.IllegalBlockSizeException;
 131import javax.crypto.NoSuchPaddingException;
 132import javax.crypto.SecretKey;
 133import javax.crypto.SecretKeyFactory;
 134import javax.crypto.spec.IvParameterSpec;
 135import javax.crypto.spec.PBEKeySpec;
 136import javax.crypto.spec.SecretKeySpec;
 137
 138class BackupManagerService extends IBackupManager.Stub {
 139    private static final String TAG = "BackupManagerService";
 140    private static final boolean DEBUG = true;
 141    private static final boolean MORE_DEBUG = false;
 142
 143    // Historical and current algorithm names
 144    static final String PBKDF_CURRENT = "PBKDF2WithHmacSHA1";
 145    static final String PBKDF_FALLBACK = "PBKDF2WithHmacSHA1And8bit";
 146
 147    // Name and current contents version of the full-backup manifest file
 148    static final String BACKUP_MANIFEST_FILENAME = "_manifest";
 149    static final int BACKUP_MANIFEST_VERSION = 1;
 150    static final String BACKUP_FILE_HEADER_MAGIC = "ANDROID BACKUP\n";
 151    static final int BACKUP_FILE_VERSION = 2;
 152    static final int BACKUP_PW_FILE_VERSION = 2;
 153    static final boolean COMPRESS_FULL_BACKUPS = true; // should be true in production
 154
 155    static final String SHARED_BACKUP_AGENT_PACKAGE = "com.android.sharedstoragebackup";
 156    static final String SERVICE_ACTION_TRANSPORT_HOST = "android.backup.TRANSPORT_HOST";
 157
 158    // How often we perform a backup pass.  Privileged external callers can
 159    // trigger an immediate pass.
 160    private static final long BACKUP_INTERVAL = AlarmManager.INTERVAL_HOUR;
 161
 162    // Random variation in backup scheduling time to avoid server load spikes
 163    private static final int FUZZ_MILLIS = 5 * 60 * 1000;
 164
 165    // The amount of time between the initial provisioning of the device and
 166    // the first backup pass.
 167    private static final long FIRST_BACKUP_INTERVAL = 12 * AlarmManager.INTERVAL_HOUR;
 168
 169    // Retry interval for clear/init when the transport is unavailable
 170    private static final long TRANSPORT_RETRY_INTERVAL = 1 * AlarmManager.INTERVAL_HOUR;
 171
 172    private static final String RUN_BACKUP_ACTION = "android.app.backup.intent.RUN";
 173    private static final String RUN_INITIALIZE_ACTION = "android.app.backup.intent.INIT";
 174    private static final String RUN_CLEAR_ACTION = "android.app.backup.intent.CLEAR";
 175    private static final int MSG_RUN_BACKUP = 1;
 176    private static final int MSG_RUN_FULL_BACKUP = 2;
 177    private static final int MSG_RUN_RESTORE = 3;
 178    private static final int MSG_RUN_CLEAR = 4;
 179    private static final int MSG_RUN_INITIALIZE = 5;
 180    private static final int MSG_RUN_GET_RESTORE_SETS = 6;
 181    private static final int MSG_TIMEOUT = 7;
 182    private static final int MSG_RESTORE_TIMEOUT = 8;
 183    private static final int MSG_FULL_CONFIRMATION_TIMEOUT = 9;
 184    private static final int MSG_RUN_FULL_RESTORE = 10;
 185    private static final int MSG_RETRY_INIT = 11;
 186    private static final int MSG_RETRY_CLEAR = 12;
 187
 188    // backup task state machine tick
 189    static final int MSG_BACKUP_RESTORE_STEP = 20;
 190    static final int MSG_OP_COMPLETE = 21;
 191
 192    // Timeout interval for deciding that a bind or clear-data has taken too long
 193    static final long TIMEOUT_INTERVAL = 10 * 1000;
 194
 195    // Timeout intervals for agent backup & restore operations
 196    static final long TIMEOUT_BACKUP_INTERVAL = 30 * 1000;
 197    static final long TIMEOUT_FULL_BACKUP_INTERVAL = 5 * 60 * 1000;
 198    static final long TIMEOUT_SHARED_BACKUP_INTERVAL = 30 * 60 * 1000;
 199    static final long TIMEOUT_RESTORE_INTERVAL = 60 * 1000;
 200
 201    // User confirmation timeout for a full backup/restore operation.  It's this long in
 202    // order to give them time to enter the backup password.
 203    static final long TIMEOUT_FULL_CONFIRMATION = 60 * 1000;
 204
 205    private Context mContext;
 206    private PackageManager mPackageManager;
 207    IPackageManager mPackageManagerBinder;
 208    private IActivityManager mActivityManager;
 209    private PowerManager mPowerManager;
 210    private AlarmManager mAlarmManager;
 211    private IMountService mMountService;
 212    IBackupManager mBackupManagerBinder;
 213
 214    boolean mEnabled;   // access to this is synchronized on 'this'
 215    boolean mProvisioned;
 216    boolean mAutoRestore;
 217    PowerManager.WakeLock mWakelock;
 218    HandlerThread mHandlerThread;
 219    BackupHandler mBackupHandler;
 220    PendingIntent mRunBackupIntent, mRunInitIntent;
 221    BroadcastReceiver mRunBackupReceiver, mRunInitReceiver;
 222    // map UIDs to the set of participating packages under that UID
 223    final SparseArray<HashSet<String>> mBackupParticipants
 224            = new SparseArray<HashSet<String>>();
 225    // set of backup services that have pending changes
 226    class BackupRequest {
 227        public String packageName;
 228
 229        BackupRequest(String pkgName) {
 230            packageName = pkgName;
 231        }
 232
 233        public String toString() {
 234            return "BackupRequest{pkg=" + packageName + "}";
 235        }
 236    }
 237    // Backups that we haven't started yet.  Keys are package names.
 238    HashMap<String,BackupRequest> mPendingBackups
 239            = new HashMap<String,BackupRequest>();
 240
 241    // Pseudoname that we use for the Package Manager metadata "package"
 242    static final String PACKAGE_MANAGER_SENTINEL = "@pm@";
 243
 244    // locking around the pending-backup management
 245    final Object mQueueLock = new Object();
 246
 247    // The thread performing the sequence of queued backups binds to each app's agent
 248    // in succession.  Bind notifications are asynchronously delivered through the
 249    // Activity Manager; use this lock object to signal when a requested binding has
 250    // completed.
 251    final Object mAgentConnectLock = new Object();
 252    IBackupAgent mConnectedAgent;
 253    volatile boolean mBackupRunning;
 254    volatile boolean mConnecting;
 255    volatile long mLastBackupPass;
 256    volatile long mNextBackupPass;
 257
 258    // For debugging, we maintain a progress trace of operations during backup
 259    static final boolean DEBUG_BACKUP_TRACE = true;
 260    final List<String> mBackupTrace = new ArrayList<String>();
 261
 262    // A similar synchronization mechanism around clearing apps' data for restore
 263    final Object mClearDataLock = new Object();
 264    volatile boolean mClearingData;
 265
 266    // Transport bookkeeping
 267    final HashMap<String,String> mTransportNames
 268            = new HashMap<String,String>();             // component name -> registration name
 269    final HashMap<String,IBackupTransport> mTransports
 270            = new HashMap<String,IBackupTransport>();   // registration name -> binder
 271    final ArrayList<TransportConnection> mTransportConnections
 272            = new ArrayList<TransportConnection>();
 273    String mCurrentTransport;
 274    ActiveRestoreSession mActiveRestoreSession;
 275
 276    // Watch the device provisioning operation during setup
 277    ContentObserver mProvisionedObserver;
 278
 279    class ProvisionedObserver extends ContentObserver {
 280        public ProvisionedObserver(Handler handler) {
 281            super(handler);
 282        }
 283
 284        public void onChange(boolean selfChange) {
 285            final boolean wasProvisioned = mProvisioned;
 286            final boolean isProvisioned = deviceIsProvisioned();
 287            // latch: never unprovision
 288            mProvisioned = wasProvisioned || isProvisioned;
 289            if (MORE_DEBUG) {
 290                Slog.d(TAG, "Provisioning change: was=" + wasProvisioned
 291                        + " is=" + isProvisioned + " now=" + mProvisioned);
 292            }
 293
 294            synchronized (mQueueLock) {
 295                if (mProvisioned && !wasProvisioned && mEnabled) {
 296                    // we're now good to go, so start the backup alarms
 297                    if (MORE_DEBUG) Slog.d(TAG, "Now provisioned, so starting backups");
 298                    startBackupAlarmsLocked(FIRST_BACKUP_INTERVAL);
 299                }
 300            }
 301        }
 302    }
 303
 304    class RestoreGetSetsParams {
 305        public IBackupTransport transport;
 306        public ActiveRestoreSession session;
 307        public IRestoreObserver observer;
 308
 309        RestoreGetSetsParams(IBackupTransport _transport, ActiveRestoreSession _session,
 310                IRestoreObserver _observer) {
 311            transport = _transport;
 312            session = _session;
 313            observer = _observer;
 314        }
 315    }
 316
 317    class RestoreParams {
 318        public IBackupTransport transport;
 319        public String dirName;
 320        public IRestoreObserver observer;
 321        public long token;
 322        public PackageInfo pkgInfo;
 323        public int pmToken; // in post-install restore, the PM's token for this transaction
 324        public boolean needFullBackup;
 325        public String[] filterSet;
 326
 327        RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
 328                long _token, PackageInfo _pkg, int _pmToken, boolean _needFullBackup) {
 329            transport = _transport;
 330            dirName = _dirName;
 331            observer = _obs;
 332            token = _token;
 333            pkgInfo = _pkg;
 334            pmToken = _pmToken;
 335            needFullBackup = _needFullBackup;
 336            filterSet = null;
 337        }
 338
 339        RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
 340                long _token, boolean _needFullBackup) {
 341            transport = _transport;
 342            dirName = _dirName;
 343            observer = _obs;
 344            token = _token;
 345            pkgInfo = null;
 346            pmToken = 0;
 347            needFullBackup = _needFullBackup;
 348            filterSet = null;
 349        }
 350
 351        RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
 352                long _token, String[] _filterSet, boolean _needFullBackup) {
 353            transport = _transport;
 354            dirName = _dirName;
 355            observer = _obs;
 356            token = _token;
 357            pkgInfo = null;
 358            pmToken = 0;
 359            needFullBackup = _needFullBackup;
 360            filterSet = _filterSet;
 361        }
 362    }
 363
 364    class ClearParams {
 365        public IBackupTransport transport;
 366        public PackageInfo packageInfo;
 367
 368        ClearParams(IBackupTransport _transport, PackageInfo _info) {
 369            transport = _transport;
 370            packageInfo = _info;
 371        }
 372    }
 373
 374    class ClearRetryParams {
 375        public String transportName;
 376        public String packageName;
 377
 378        ClearRetryParams(String transport, String pkg) {
 379            transportName = transport;
 380            packageName = pkg;
 381        }
 382    }
 383
 384    class FullParams {
 385        public ParcelFileDescriptor fd;
 386        public final AtomicBoolean latch;
 387        public IFullBackupRestoreObserver observer;
 388        public String curPassword;     // filled in by the confirmation step
 389        public String encryptPassword;
 390
 391        FullParams() {
 392            latch = new AtomicBoolean(false);
 393        }
 394    }
 395
 396    class FullBackupParams extends FullParams {
 397        public boolean includeApks;
 398        public boolean includeObbs;
 399        public boolean includeShared;
 400        public boolean allApps;
 401        public boolean includeSystem;
 402        public String[] packages;
 403
 404        FullBackupParams(ParcelFileDescriptor output, boolean saveApks, boolean saveObbs,
 405                boolean saveShared, boolean doAllApps, boolean doSystem, String[] pkgList) {
 406            fd = output;
 407            includeApks = saveApks;
 408            includeObbs = saveObbs;
 409            includeShared = saveShared;
 410            allApps = doAllApps;
 411            includeSystem = doSystem;
 412            packages = pkgList;
 413        }
 414    }
 415
 416    class FullRestoreParams extends FullParams {
 417        FullRestoreParams(ParcelFileDescriptor input) {
 418            fd = input;
 419        }
 420    }
 421
 422    // Bookkeeping of in-flight operations for timeout etc. purposes.  The operation
 423    // token is the index of the entry in the pending-operations list.
 424    static final int OP_PENDING = 0;
 425    static final int OP_ACKNOWLEDGED = 1;
 426    static final int OP_TIMEOUT = -1;
 427
 428    class Operation {
 429        public int state;
 430        public BackupRestoreTask callback;
 431
 432        Operation(int initialState, BackupRestoreTask callbackObj) {
 433            state = initialState;
 434            callback = callbackObj;
 435        }
 436    }
 437    final SparseArray<Operation> mCurrentOperations = new SparseArray<Operation>();
 438    final Object mCurrentOpLock = new Object();
 439    final Random mTokenGenerator = new Random();
 440
 441    final SparseArray<FullParams> mFullConfirmations = new SparseArray<FullParams>();
 442
 443    // Where we keep our journal files and other bookkeeping
 444    File mBaseStateDir;
 445    File mDataDir;
 446    File mJournalDir;
 447    File mJournal;
 448
 449    // Backup password, if any, and the file where it's saved.  What is stored is not the
 450    // password text itself; it's the result of a PBKDF2 hash with a randomly chosen (but
 451    // persisted) salt.  Validation is performed by running the challenge text through the
 452    // same PBKDF2 cycle with the persisted salt; if the resulting derived key string matches
 453    // the saved hash string, then the challenge text matches the originally supplied
 454    // password text.
 455    private final SecureRandom mRng = new SecureRandom();
 456    private String mPasswordHash;
 457    private File mPasswordHashFile;
 458    private int mPasswordVersion;
 459    private File mPasswordVersionFile;
 460    private byte[] mPasswordSalt;
 461
 462    // Configuration of PBKDF2 that we use for generating pw hashes and intermediate keys
 463    static final int PBKDF2_HASH_ROUNDS = 10000;
 464    static final int PBKDF2_KEY_SIZE = 256;     // bits
 465    static final int PBKDF2_SALT_SIZE = 512;    // bits
 466    static final String ENCRYPTION_ALGORITHM_NAME = "AES-256";
 467
 468    // Keep a log of all the apps we've ever backed up, and what the
 469    // dataset tokens are for both the current backup dataset and
 470    // the ancestral dataset.
 471    private File mEverStored;
 472    HashSet<String> mEverStoredApps = new HashSet<String>();
 473
 474    static final int CURRENT_ANCESTRAL_RECORD_VERSION = 1;  // increment when the schema changes
 475    File mTokenFile;
 476    Set<String> mAncestralPackages = null;
 477    long mAncestralToken = 0;
 478    long mCurrentToken = 0;
 479
 480    // Persistently track the need to do a full init
 481    static final String INIT_SENTINEL_FILE_NAME = "_need_init_";
 482    HashSet<String> mPendingInits = new HashSet<String>();  // transport names
 483
 484    // Utility: build a new random integer token
 485    int generateToken() {
 486        int token;
 487        do {
 488            synchronized (mTokenGenerator) {
 489                token = mTokenGenerator.nextInt();
 490            }
 491        } while (token < 0);
 492        return token;
 493    }
 494
 495    // ----- Asynchronous backup/restore handler thread -----
 496
 497    private class BackupHandler extends Handler {
 498        public BackupHandler(Looper looper) {
 499            super(looper);
 500        }
 501
 502        public void handleMessage(Message msg) {
 503
 504            switch (msg.what) {
 505            case MSG_RUN_BACKUP:
 506            {
 507                mLastBackupPass = System.currentTimeMillis();
 508                mNextBackupPass = mLastBackupPass + BACKUP_INTERVAL;
 509
 510                IBackupTransport transport = getTransport(mCurrentTransport);
 511                if (transport == null) {
 512                    Slog.v(TAG, "Backup requested but no transport available");
 513                    synchronized (mQueueLock) {
 514                        mBackupRunning = false;
 515                    }
 516                    mWakelock.release();
 517                    break;
 518                }
 519
 520                // snapshot the pending-backup set and work on that
 521                ArrayList<BackupRequest> queue = new ArrayList<BackupRequest>();
 522                File oldJournal = mJournal;
 523                synchronized (mQueueLock) {
 524                    // Do we have any work to do?  Construct the work queue
 525                    // then release the synchronization lock to actually run
 526                    // the backup.
 527                    if (mPendingBackups.size() > 0) {
 528                        for (BackupRequest b: mPendingBackups.values()) {
 529                            queue.add(b);
 530                        }
 531                        if (DEBUG) Slog.v(TAG, "clearing pending backups");
 532                        mPendingBackups.clear();
 533
 534                        // Start a new backup-queue journal file too
 535                        mJournal = null;
 536
 537                    }
 538                }
 539
 540                // At this point, we have started a new journal file, and the old
 541                // file identity is being passed to the backup processing task.
 542                // When it completes successfully, that old journal file will be
 543                // deleted.  If we crash prior to that, the old journal is parsed
 544                // at next boot and the journaled requests fulfilled.
 545                boolean staged = true;
 546                if (queue.size() > 0) {
 547                    // Spin up a backup state sequence and set it running
 548                    try {
 549                        String dirName = transport.transportDirName();
 550                        PerformBackupTask pbt = new PerformBackupTask(transport, dirName,
 551                                queue, oldJournal);
 552                        Message pbtMessage = obtainMessage(MSG_BACKUP_RESTORE_STEP, pbt);
 553                        sendMessage(pbtMessage);
 554                    } catch (RemoteException e) {
 555                        // unable to ask the transport its dir name -- transient failure, since
 556                        // the above check succeeded.  Try again next time.
 557                        Slog.e(TAG, "Transport became unavailable attempting backup");
 558                        staged = false;
 559                    }
 560                } else {
 561                    Slog.v(TAG, "Backup requested but nothing pending");
 562                    staged = false;
 563                }
 564
 565                if (!staged) {
 566                    // if we didn't actually hand off the wakelock, rewind until next time
 567                    synchronized (mQueueLock) {
 568                        mBackupRunning = false;
 569                    }
 570                    mWakelock.release();
 571                }
 572                break;
 573            }
 574
 575            case MSG_BACKUP_RESTORE_STEP:
 576            {
 577                try {
 578                    BackupRestoreTask task = (BackupRestoreTask) msg.obj;
 579                    if (MORE_DEBUG) Slog.v(TAG, "Got next step for " + task + ", executing");
 580                    task.execute();
 581                } catch (ClassCastException e) {
 582                    Slog.e(TAG, "Invalid backup task in flight, obj=" + msg.obj);
 583                }
 584                break;
 585            }
 586
 587            case MSG_OP_COMPLETE:
 588            {
 589                try {
 590                    BackupRestoreTask task = (BackupRestoreTask) msg.obj;
 591                    task.operationComplete();
 592                } catch (ClassCastException e) {
 593                    Slog.e(TAG, "Invalid completion in flight, obj=" + msg.obj);
 594                }
 595                break;
 596            }
 597
 598            case MSG_RUN_FULL_BACKUP:
 599            {
 600                // TODO: refactor full backup to be a looper-based state machine
 601                // similar to normal backup/restore.
 602                FullBackupParams params = (FullBackupParams)msg.obj;
 603                PerformFullBackupTask task = new PerformFullBackupTask(params.fd,
 604                        params.observer, params.includeApks, params.includeObbs,
 605                        params.includeShared, params.curPassword, params.encryptPassword,
 606                        params.allApps, params.includeSystem, params.packages, params.latch);
 607                (new Thread(task)).start();
 608                break;
 609            }
 610
 611            case MSG_RUN_RESTORE:
 612            {
 613                RestoreParams params = (RestoreParams)msg.obj;
 614                Slog.d(TAG, "MSG_RUN_RESTORE observer=" + params.observer);
 615                PerformRestoreTask task = new PerformRestoreTask(
 616                        params.transport, params.dirName, params.observer,
 617                        params.token, params.pkgInfo, params.pmToken,
 618                        params.needFullBackup, params.filterSet);
 619                Message restoreMsg = obtainMessage(MSG_BACKUP_RESTORE_STEP, task);
 620                sendMessage(restoreMsg);
 621                break;
 622            }
 623
 624            case MSG_RUN_FULL_RESTORE:
 625            {
 626                // TODO: refactor full restore to be a looper-based state machine
 627                // similar to normal backup/restore.
 628                FullRestoreParams params = (FullRestoreParams)msg.obj;
 629                PerformFullRestoreTask task = new PerformFullRestoreTask(params.fd,
 630                        params.curPassword, params.encryptPassword,
 631                        params.observer, params.latch);
 632                (new Thread(task)).start();
 633                break;
 634            }
 635
 636            case MSG_RUN_CLEAR:
 637            {
 638                ClearParams params = (ClearParams)msg.obj;
 639                (new PerformClearTask(params.transport, params.packageInfo)).run();
 640                break;
 641            }
 642
 643            case MSG_RETRY_CLEAR:
 644            {
 645                // reenqueues if the transport remains unavailable
 646                ClearRetryParams params = (ClearRetryParams)msg.obj;
 647                clearBackupData(params.transportName, params.packageName);
 648                break;
 649            }
 650
 651            case MSG_RUN_INITIALIZE:
 652            {
 653                HashSet<String> queue;
 654
 655                // Snapshot the pending-init queue and work on that
 656                synchronized (mQueueLock) {
 657                    queue = new HashSet<String>(mPendingInits);
 658                    mPendingInits.clear();
 659                }
 660
 661                (new PerformInitializeTask(queue)).run();
 662                break;
 663            }
 664
 665            case MSG_RETRY_INIT:
 666            {
 667                synchronized (mQueueLock) {
 668                    recordInitPendingLocked(msg.arg1 != 0, (String)msg.obj);
 669                    mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
 670                            mRunInitIntent);
 671                }
 672                break;
 673            }
 674
 675            case MSG_RUN_GET_RESTORE_SETS:
 676            {
 677                // Like other async operations, this is entered with the wakelock held
 678                RestoreSet[] sets = null;
 679                RestoreGetSetsParams params = (RestoreGetSetsParams)msg.obj;
 680                try {
 681                    sets = params.transport.getAvailableRestoreSets();
 682                    // cache the result in the active session
 683                    synchronized (params.session) {
 684                        params.session.mRestoreSets = sets;
 685                    }
 686                    if (sets == null) EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
 687                } catch (Exception e) {
 688                    Slog.e(TAG, "Error from transport getting set list");
 689                } finally {
 690                    if (params.observer != null) {
 691                        try {
 692                            params.observer.restoreSetsAvailable(sets);
 693                        } catch (RemoteException re) {
 694                            Slog.e(TAG, "Unable to report listing to observer");
 695                        } catch (Exception e) {
 696                            Slog.e(TAG, "Restore observer threw", e);
 697                        }
 698                    }
 699
 700                    // Done: reset the session timeout clock
 701                    removeMessages(MSG_RESTORE_TIMEOUT);
 702                    sendEmptyMessageDelayed(MSG_RESTORE_TIMEOUT, TIMEOUT_RESTORE_INTERVAL);
 703
 704                    mWakelock.release();
 705                }
 706                break;
 707            }
 708
 709            case MSG_TIMEOUT:
 710            {
 711                handleTimeout(msg.arg1, msg.obj);
 712                break;
 713            }
 714
 715            case MSG_RESTORE_TIMEOUT:
 716            {
 717                synchronized (BackupManagerService.this) {
 718                    if (mActiveRestoreSession != null) {
 719                        // Client app left the restore session dangling.  We know that it
 720                        // can't be in the middle of an actual restore operation because
 721                        // the timeout is suspended while a restore is in progress.  Clean
 722                        // up now.
 723                        Slog.w(TAG, "Restore session timed out; aborting");
 724                        post(mActiveRestoreSession.new EndRestoreRunnable(
 725                                BackupManagerService.this, mActiveRestoreSession));
 726                    }
 727                }
 728            }
 729
 730            case MSG_FULL_CONFIRMATION_TIMEOUT:
 731            {
 732                synchronized (mFullConfirmations) {
 733                    FullParams params = mFullConfirmations.get(msg.arg1);
 734                    if (params != null) {
 735                        Slog.i(TAG, "Full backup/restore timed out waiting for user confirmation");
 736
 737                        // Release the waiter; timeout == completion
 738                        signalFullBackupRestoreCompletion(params);
 739
 740                        // Remove the token from the set
 741                        mFullConfirmations.delete(msg.arg1);
 742
 743                        // Report a timeout to the observer, if any
 744                        if (params.observer != null) {
 745                            try {
 746                                params.observer.onTimeout();
 747                            } catch (RemoteException e) {
 748                                /* don't care if the app has gone away */
 749                            }
 750                        }
 751                    } else {
 752                        Slog.d(TAG, "couldn't find params for token " + msg.arg1);
 753                    }
 754                }
 755                break;
 756            }
 757            }
 758        }
 759    }
 760
 761    // ----- Debug-only backup operation trace -----
 762    void addBackupTrace(String s) {
 763        if (DEBUG_BACKUP_TRACE) {
 764            synchronized (mBackupTrace) {
 765                mBackupTrace.add(s);
 766            }
 767        }
 768    }
 769
 770    void clearBackupTrace() {
 771        if (DEBUG_BACKUP_TRACE) {
 772            synchronized (mBackupTrace) {
 773                mBackupTrace.clear();
 774            }
 775        }
 776    }
 777
 778    // ----- Main service implementation -----
 779
 780    public BackupManagerService(Context context) {
 781        mContext = context;
 782        mPackageManager = context.getPackageManager();
 783        mPackageManagerBinder = AppGlobals.getPackageManager();
 784        mActivityManager = ActivityManagerNative.getDefault();
 785
 786        mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
 787        mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
 788        mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
 789
 790        mBackupManagerBinder = asInterface(asBinder());
 791
 792        // spin up the backup/restore handler thread
 793        mHandlerThread = new HandlerThread("backup", Process.THREAD_PRIORITY_BACKGROUND);
 794        mHandlerThread.start();
 795        mBackupHandler = new BackupHandler(mHandlerThread.getLooper());
 796
 797        // Set up our bookkeeping
 798        final ContentResolver resolver = context.getContentResolver();
 799        boolean areEnabled = Settings.Secure.getInt(resolver,
 800                Settings.Secure.BACKUP_ENABLED, 0) != 0;
 801        mProvisioned = Settings.Global.getInt(resolver,
 802                Settings.Global.DEVICE_PROVISIONED, 0) != 0;
 803        mAutoRestore = Settings.Secure.getInt(resolver,
 804                Settings.Secure.BACKUP_AUTO_RESTORE, 1) != 0;
 805
 806        mProvisionedObserver = new ProvisionedObserver(mBackupHandler);
 807        resolver.registerContentObserver(
 808                Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED),
 809                false, mProvisionedObserver);
 810
 811        // If Encrypted file systems is enabled or disabled, this call will return the
 812        // correct directory.
 813        mBaseStateDir = new File(Environment.getSecureDataDirectory(), "backup");
 814        mBaseStateDir.mkdirs();
 815        if (!SELinux.restorecon(mBaseStateDir)) {
 816            Slog.e(TAG, "SELinux restorecon failed on " + mBaseStateDir);
 817        }
 818        mDataDir = Environment.getDownloadCacheDirectory();
 819
 820        mPasswordVersion = 1;       // unless we hear otherwise
 821        mPasswordVersionFile = new File(mBaseStateDir, "pwversion");
 822        if (mPasswordVersionFile.exists()) {
 823            FileInputStream fin = null;
 824            DataInputStream in = null;
 825            try {
 826                fin = new FileInputStream(mPasswordVersionFile);
 827                in = new DataInputStream(fin);
 828                mPasswordVersion = in.readInt();
 829            } catch (IOException e) {
 830                Slog.e(TAG, "Unable to read backup pw version");
 831            } finally {
 832                try {
 833                    if (in != null) in.close();
 834                    if (fin != null) fin.close();
 835                } catch (IOException e) {
 836                    Slog.w(TAG, "Error closing pw version files");
 837                }
 838            }
 839        }
 840
 841        mPasswordHashFile = new File(mBaseStateDir, "pwhash");
 842        if (mPasswordHashFile.exists()) {
 843            FileInputStream fin = null;
 844            DataInputStream in = null;
 845            try {
 846                fin = new FileInputStream(mPasswordHashFile);
 847                in = new DataInputStream(new BufferedInputStream(fin));
 848                // integer length of the salt array, followed by the salt,
 849                // then the hex pw hash string
 850                int saltLen = in.readInt();
 851                byte[] salt = new byte[saltLen];
 852                in.readFully(salt);
 853                mPasswordHash = in.readUTF();
 854                mPasswordSalt = salt;
 855            } catch (IOException e) {
 856                Slog.e(TAG, "Unable to read saved backup pw hash");
 857            } finally {
 858                try {
 859                    if (in != null) in.close();
 860                    if (fin != null) fin.close();
 861                } catch (IOException e) {
 862                    Slog.w(TAG, "Unable to close streams");
 863                }
 864            }
 865        }
 866
 867        // Alarm receivers for scheduled backups & initialization operations
 868        mRunBackupReceiver = new RunBackupReceiver();
 869        IntentFilter filter = new IntentFilter();
 870        filter.addAction(RUN_BACKUP_ACTION);
 871        context.registerReceiver(mRunBackupReceiver, filter,
 872                android.Manifest.permission.BACKUP, null);
 873
 874        mRunInitReceiver = new RunInitializeReceiver();
 875        filter = new IntentFilter();
 876        filter.addAction(RUN_INITIALIZE_ACTION);
 877        context.registerReceiver(mRunInitReceiver, filter,
 878                android.Manifest.permission.BACKUP, null);
 879
 880        Intent backupIntent = new Intent(RUN_BACKUP_ACTION);
 881        backupIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
 882        mRunBackupIntent = PendingIntent.getBroadcast(context, MSG_RUN_BACKUP, backupIntent, 0);
 883
 884        Intent initIntent = new Intent(RUN_INITIALIZE_ACTION);
 885        backupIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
 886        mRunInitIntent = PendingIntent.getBroadcast(context, MSG_RUN_INITIALIZE, initIntent, 0);
 887
 888        // Set up the backup-request journaling
 889        mJournalDir = new File(mBaseStateDir, "pending");
 890        mJournalDir.mkdirs();   // creates mBaseStateDir along the way
 891        mJournal = null;        // will be created on first use
 892
 893        // Set up the various sorts of package tracking we do
 894        initPackageTracking();
 895
 896        // Build our mapping of uid to backup client services.  This implicitly
 897        // schedules a backup pass on the Package Manager metadata the first
 898        // time anything needs to be backed up.
 899        synchronized (mBackupParticipants) {
 900            addPackageParticipantsLocked(null);
 901        }
 902
 903        // Set up our transport options and initialize the default transport
 904        // TODO: Don't create transports that we don't need to?
 905        mCurrentTransport = Settings.Secure.getString(context.getContentResolver(),
 906                Settings.Secure.BACKUP_TRANSPORT);
 907        if ("".equals(mCurrentTransport)) {
 908            mCurrentTransport = null;
 909        }
 910        if (DEBUG) Slog.v(TAG, "Starting with transport " + mCurrentTransport);
 911
 912        // Find transport hosts and bind to their services
 913        Intent transportServiceIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST);
 914        List<ResolveInfo> hosts = mPackageManager.queryIntentServicesAsUser(
 915                transportServiceIntent, 0, UserHandle.USER_OWNER);
 916        if (DEBUG) {
 917            Slog.v(TAG, "Found transports: " + ((hosts == null) ? "null" : hosts.size()));
 918        }
 919        if (hosts != null) {
 920            if (MORE_DEBUG) {
 921                for (int i = 0; i < hosts.size(); i++) {
 922                    ServiceInfo info = hosts.get(i).serviceInfo;
 923                    Slog.v(TAG, "   " + info.packageName + "/" + info.name);
 924                }
 925            }
 926            for (int i = 0; i < hosts.size(); i++) {
 927                try {
 928                    ServiceInfo info = hosts.get(i).serviceInfo;
 929                    PackageInfo packInfo = mPackageManager.getPackageInfo(info.packageName, 0);
 930                    if ((packInfo.applicationInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
 931                        ComponentName svcName = new ComponentName(info.packageName, info.name);
 932                        if (DEBUG) {
 933                            Slog.i(TAG, "Binding to transport host " + svcName);
 934                        }
 935                        Intent intent = new Intent(transportServiceIntent);
 936                        intent.setComponent(svcName);
 937                        TransportConnection connection = new TransportConnection();
 938                        mTransportConnections.add(connection);
 939                        context.bindServiceAsUser(intent,
 940                                connection, Context.BIND_AUTO_CREATE,
 941                                UserHandle.OWNER);
 942                    } else {
 943                        Slog.w(TAG, "Transport package not privileged: " + info.packageName);
 944                    }
 945                } catch (Exception e) {
 946                    Slog.e(TAG, "Problem resolving transport service: " + e.getMessage());
 947                }
 948            }
 949        }
 950
 951        // Now that we know about valid backup participants, parse any
 952        // leftover journal files into the pending backup set
 953        parseLeftoverJournals();
 954
 955        // Power management
 956        mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*");
 957
 958        // Start the backup passes going
 959        setBackupEnabled(areEnabled);
 960    }
 961
 962    private class RunBackupReceiver extends BroadcastReceiver {
 963        public void onReceive(Context context, Intent intent) {
 964            if (RUN_BACKUP_ACTION.equals(intent.getAction())) {
 965                synchronized (mQueueLock) {
 966                    if (mPendingInits.size() > 0) {
 967                        // If there are pending init operations, we process those
 968                        // and then settle into the usual periodic backup schedule.
 969                        if (DEBUG) Slog.v(TAG, "Init pending at scheduled backup");
 970                        try {
 971                            mAlarmManager.cancel(mRunInitIntent);
 972                            mRunInitIntent.send();
 973                        } catch (PendingIntent.CanceledException ce) {
 974                            Slog.e(TAG, "Run init intent cancelled");
 975                            // can't really do more than bail here
 976                        }
 977                    } else {
 978                        // Don't run backups now if we're disabled or not yet
 979                        // fully set up.
 980                        if (mEnabled && mProvisioned) {
 981                            if (!mBackupRunning) {
 982                                if (DEBUG) Slog.v(TAG, "Running a backup pass");
 983
 984                                // Acquire the wakelock and pass it to the backup thread.  it will
 985                                // be released once backup concludes.
 986                                mBackupRunning = true;
 987                                mWakelock.acquire();
 988
 989                                Message msg = mBackupHandler.obtainMessage(MSG_RUN_BACKUP);
 990                                mBackupHandler.sendMessage(msg);
 991                            } else {
 992                                Slog.i(TAG, "Backup time but one already running");
 993                            }
 994                        } else {
 995                            Slog.w(TAG, "Backup pass but e=" + mEnabled + " p=" + mProvisioned);
 996                        }
 997                    }
 998                }
 999            }
1000        }
1001    }
1002
1003    private class RunInitializeReceiver extends BroadcastReceiver {
1004        public void onReceive(Context context, Intent intent) {
1005            if (RUN_INITIALIZE_ACTION.equals(intent.getAction())) {
1006                synchronized (mQueueLock) {
1007                    if (DEBUG) Slog.v(TAG, "Running a device init");
1008
1009                    // Acquire the wakelock and pass it to the init thread.  it will
1010                    // be released once init concludes.
1011                    mWakelock.acquire();
1012
1013                    Message msg = mBackupHandler.obtainMessage(MSG_RUN_INITIALIZE);
1014                    mBackupHandler.sendMessage(msg);
1015                }
1016            }
1017        }
1018    }
1019
1020    private void initPackageTracking() {
1021        if (DEBUG) Slog.v(TAG, "Initializing package tracking");
1022
1023        // Remember our ancestral dataset
1024        mTokenFile = new File(mBaseStateDir, "ancestral");
1025        try {
1026            RandomAccessFile tf = new RandomAccessFile(mTokenFile, "r");
1027            int version = tf.readInt();
1028            if (version == CURRENT_ANCESTRAL_RECORD_VERSION) {
1029                mAncestralToken = tf.readLong();
1030                mCurrentToken = tf.readLong();
1031
1032                int numPackages = tf.readInt();
1033                if (numPackages >= 0) {
1034                    mAncestralPackages = new HashSet<String>();
1035                    for (int i = 0; i < numPackages; i++) {
1036                        String pkgName = tf.readUTF();
1037                        mAncestralPackages.add(pkgName);
1038                    }
1039                }
1040            }
1041            tf.close();
1042        } catch (FileNotFoundException fnf) {
1043            // Probably innocuous
1044            Slog.v(TAG, "No ancestral data");
1045        } catch (IOException e) {
1046            Slog.w(TAG, "Unable to read token file", e);
1047        }
1048
1049        // Keep a log of what apps we've ever backed up.  Because we might have
1050        // rebooted in the middle of an operation that was removing something from
1051        // this log, we sanity-check its contents here and reconstruct it.
1052        mEverStored = new File(mBaseStateDir, "processed");
1053        File tempProcessedFile = new File(mBaseStateDir, "processed.new");
1054
1055        // If we were in the middle of removing something from the ever-backed-up
1056        // file, there might be a transient "processed.new" file still present.
1057        // Ignore it -- we'll validate "processed" against the current package set.
1058        if (tempProcessedFile.exists()) {
1059            tempProcessedFile.delete();
1060        }
1061
1062        // If there are previous contents, parse them out then start a new
1063        // file to continue the recordkeeping.
1064        if (mEverStored.exists()) {
1065            RandomAccessFile temp = null;
1066            RandomAccessFile in = null;
1067
1068            try {
1069                temp = new RandomAccessFile(tempProcessedFile, "rws");
1070                in = new RandomAccessFile(mEverStored, "r");
1071
1072                while (true) {
1073                    PackageInfo info;
1074                    String pkg = in.readUTF();
1075                    try {
1076                        info = mPackageManager.getPackageInfo(pkg, 0);
1077                        mEverStoredApps.add(pkg);
1078                        temp.writeUTF(pkg);
1079                        if (MORE_DEBUG) Slog.v(TAG, "   + " + pkg);
1080                    } catch (NameNotFoundException e) {
1081                        // nope, this package was uninstalled; don't include it
1082                        if (MORE_DEBUG) Slog.v(TAG, "   - " + pkg);
1083                    }
1084                }
1085            } catch (EOFException e) {
1086                // Once we've rewritten the backup history log, atomically replace the
1087                // old one with the new one then reopen the file for continuing use.
1088                if (!tempProcessedFile.renameTo(mEverStored)) {
1089                    Slog.e(TAG, "Error renaming " + tempProcessedFile + " to " + mEverStored);
1090                }
1091            } catch (IOException e) {
1092                Slog.e(TAG, "Error in processed file", e);
1093            } finally {
1094                try { if (temp != null) temp.close(); } catch (IOException e) {}
1095                try { if (in != null) in.close(); } catch (IOException e) {}
1096            }
1097        }
1098
1099        // Register for broadcasts about package install, etc., so we can
1100        // update the provider list.
1101        IntentFilter filter = new IntentFilter();
1102        filter.addAction(Intent.ACTION_PACKAGE_ADDED);
1103        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1104        filter.addDataScheme("package");
1105        mContext.registerReceiver(mBroadcastReceiver, filter);
1106        // Register for events related to sdcard installation.
1107        IntentFilter sdFilter = new IntentFilter();
1108        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
1109        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
1110        mContext.registerReceiver(mBroadcastReceiver, sdFilter);
1111    }
1112
1113    private void parseLeftoverJournals() {
1114        for (File f : mJournalDir.listFiles()) {
1115            if (mJournal == null || f.compareTo(mJournal) != 0) {
1116                // This isn't the current journal, so it must be a leftover.  Read
1117                // out the package names mentioned there and schedule them for
1118                // backup.
1119                RandomAccessFile in = null;
1120                try {
1121                    Slog.i(TAG, "Found stale backup journal, scheduling");
1122                    in = new RandomAccessFile(f, "r");
1123                    while (true) {
1124                        String packageName = in.readUTF();
1125                        Slog.i(TAG, "  " + packageName);
1126                        dataChangedImpl(packageName);
1127                    }
1128                } catch (EOFException e) {
1129                    // no more data; we're done
1130                } catch (Exception e) {
1131                    Slog.e(TAG, "Can't read " + f, e);
1132                } finally {
1133                    // close/delete the file
1134                    try { if (in != null) in.close(); } catch (IOException e) {}
1135                    f.delete();
1136                }
1137            }
1138        }
1139    }
1140
1141    private SecretKey buildPasswordKey(String algorithm, String pw, byte[] salt, int rounds) {
1142        return buildCharArrayKey(algorithm, pw.toCharArray(), salt, rounds);
1143    }
1144
1145    private SecretKey buildCharArrayKey(String algorithm, char[] pwArray, byte[] salt, int rounds) {
1146        try {
1147            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm);
1148            KeySpec ks = new PBEKeySpec(pwArray, salt, rounds, PBKDF2_KEY_SIZE);
1149            return keyFactory.generateSecret(ks);
1150        } catch (InvalidKeySpecException e) {
1151            Slog.e(TAG, "Invalid key spec for PBKDF2!");
1152        } catch (NoSuchAlgorithmException e) {
1153            Slog.e(TAG, "PBKDF2 unavailable!");
1154        }
1155        return null;
1156    }
1157
1158    private String buildPasswordHash(String algorithm, String pw, byte[] salt, int rounds) {
1159        SecretKey key = buildPasswordKey(algorithm, pw, salt, rounds);
1160        if (key != null) {
1161            return byteArrayToHex(key.getEncoded());
1162        }
1163        return null;
1164    }
1165
1166    private String byteArrayToHex(byte[] data) {
1167        StringBuilder buf = new StringBuilder(data.length * 2);
1168        for (int i = 0; i < data.length; i++) {
1169            buf.append(Byte.toHexString(data[i], true));
1170        }
1171        return buf.toString();
1172    }
1173
1174    private byte[] hexToByteArray(String digits) {
1175        final int bytes = digits.length() / 2;
1176        if (2*bytes != digits.length()) {
1177            throw new IllegalArgumentException("Hex string must have an even number of digits");
1178        }
1179
1180        byte[] result = new byte[bytes];
1181        for (int i = 0; i < digits.length(); i += 2) {
1182            result[i/2] = (byte) Integer.parseInt(digits.substring(i, i+2), 16);
1183        }
1184        return result;
1185    }
1186
1187    private byte[] makeKeyChecksum(String algorithm, byte[] pwBytes, byte[] salt, int rounds) {
1188        char[] mkAsChar = new char[pwBytes.length];
1189        for (int i = 0; i < pwBytes.length; i++) {
1190            mkAsChar[i] = (char) pwBytes[i];
1191        }
1192
1193        Key checksum = buildCharArrayKey(algorithm, mkAsChar, salt, rounds);
1194        return checksum.getEncoded();
1195    }
1196
1197    // Used for generating random salts or passwords
1198    private byte[] randomBytes(int bits) {
1199        byte[] array = new byte[bits / 8];
1200        mRng.nextBytes(array);
1201        return array;
1202    }
1203
1204    // Backup password management
1205    boolean passwordMatchesSaved(String algorithm, String candidatePw, int rounds) {
1206        // First, on an encrypted device we require matching the device pw
1207        final boolean isEncrypted;
1208        try {
1209            isEncrypted = (mMountService.getEncryptionState() != MountService.ENCRYPTION_STATE_NONE);
1210  

Large files files are truncated, but you can click here to view the full file