PerformAdbBackupTask.java revision f251e3509838e3fbc62ccdba9d4cfd0527f67acd
1f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov/* 2f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov * Copyright (C) 2017 The Android Open Source Project 3f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov * 4f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov * Licensed under the Apache License, Version 2.0 (the "License"); 5f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov * you may not use this file except in compliance with the License. 6f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov * You may obtain a copy of the License at 7f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov * 8f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov * http://www.apache.org/licenses/LICENSE-2.0 9f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov * 10f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov * Unless required by applicable law or agreed to in writing, software 11f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov * distributed under the License is distributed on an "AS IS" BASIS, 12f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov * See the License for the specific language governing permissions and 14f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov * limitations under the License 15f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov */ 16f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 17f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovpackage com.android.server.backup.fullbackup; 18f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 19f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovimport android.app.backup.IFullBackupRestoreObserver; 20f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovimport android.content.pm.ApplicationInfo; 21f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovimport android.content.pm.PackageInfo; 22f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovimport android.content.pm.PackageManager; 23f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovimport android.content.pm.PackageManager.NameNotFoundException; 24f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovimport android.os.ParcelFileDescriptor; 25f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovimport android.os.RemoteException; 26f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovimport android.os.UserHandle; 27f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovimport android.util.Slog; 28f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovimport com.android.server.AppWidgetBackupBridge; 29f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovimport com.android.server.backup.BackupRestoreTask; 30f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovimport com.android.server.backup.KeyValueAdbBackupEngine; 31f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovimport com.android.server.backup.RefactoredBackupManagerService; 32f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovimport java.io.ByteArrayOutputStream; 33f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovimport java.io.DataOutputStream; 34f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovimport java.io.FileOutputStream; 35f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovimport java.io.IOException; 36f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovimport java.io.OutputStream; 37f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovimport java.util.ArrayList; 38f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovimport java.util.Arrays; 39f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovimport java.util.Iterator; 40f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovimport java.util.List; 41f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovimport java.util.Map.Entry; 42f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovimport java.util.TreeMap; 43f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovimport java.util.concurrent.atomic.AtomicBoolean; 44f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovimport java.util.zip.Deflater; 45f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovimport java.util.zip.DeflaterOutputStream; 46f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovimport javax.crypto.Cipher; 47f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovimport javax.crypto.CipherOutputStream; 48f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovimport javax.crypto.SecretKey; 49f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovimport javax.crypto.spec.SecretKeySpec; 50f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 51f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov/** 52f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov * Full backup task variant used for adb backup. 53f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov */ 54f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovpublic class PerformAdbBackupTask extends FullBackupTask implements BackupRestoreTask { 55f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 56f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov private RefactoredBackupManagerService backupManagerService; 57f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov FullBackupEngine mBackupEngine; 58f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov final AtomicBoolean mLatch; 59f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 60f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov ParcelFileDescriptor mOutputFile; 61f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov DeflaterOutputStream mDeflater; 62f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov boolean mIncludeApks; 63f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov boolean mIncludeObbs; 64f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov boolean mIncludeShared; 65f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov boolean mDoWidgets; 66f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov boolean mAllApps; 67f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov boolean mIncludeSystem; 68f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov boolean mCompress; 69f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov boolean mKeyValue; 70f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov ArrayList<String> mPackages; 71f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov PackageInfo mCurrentTarget; 72f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov String mCurrentPassword; 73f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov String mEncryptPassword; 74f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov private final int mCurrentOpToken; 75f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 76f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov public PerformAdbBackupTask(RefactoredBackupManagerService backupManagerService, 77f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov ParcelFileDescriptor fd, IFullBackupRestoreObserver observer, 78f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov boolean includeApks, boolean includeObbs, boolean includeShared, boolean doWidgets, 79f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov String curPassword, String encryptPassword, boolean doAllApps, boolean doSystem, 80f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov boolean doCompress, boolean doKeyValue, String[] packages, AtomicBoolean latch) { 81f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov super(observer); 82f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov this.backupManagerService = backupManagerService; 83f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov mCurrentOpToken = backupManagerService.generateRandomIntegerToken(); 84f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov mLatch = latch; 85f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 86f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov mOutputFile = fd; 87f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov mIncludeApks = includeApks; 88f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov mIncludeObbs = includeObbs; 89f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov mIncludeShared = includeShared; 90f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov mDoWidgets = doWidgets; 91f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov mAllApps = doAllApps; 92f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov mIncludeSystem = doSystem; 93f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov mPackages = (packages == null) 94f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov ? new ArrayList<String>() 95f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov : new ArrayList<>(Arrays.asList(packages)); 96f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov mCurrentPassword = curPassword; 97f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // when backing up, if there is a current backup password, we require that 98f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // the user use a nonempty encryption password as well. if one is supplied 99f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // in the UI we use that, but if the UI was left empty we fall back to the 100f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // current backup password (which was supplied by the user as well). 101f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov if (encryptPassword == null || "".equals(encryptPassword)) { 102f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov mEncryptPassword = curPassword; 103f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } else { 104f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov mEncryptPassword = encryptPassword; 105f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 106f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov if (RefactoredBackupManagerService.MORE_DEBUG) { 107f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov Slog.w(RefactoredBackupManagerService.TAG, "Encrypting backup with passphrase=" + mEncryptPassword); 108f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 109f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov mCompress = doCompress; 110f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov mKeyValue = doKeyValue; 111f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 112f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 113f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov void addPackagesToSet(TreeMap<String, PackageInfo> set, List<String> pkgNames) { 114f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov for (String pkgName : pkgNames) { 115f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov if (!set.containsKey(pkgName)) { 116f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov try { 117f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov PackageInfo info = backupManagerService.mPackageManager.getPackageInfo(pkgName, 118f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov PackageManager.GET_SIGNATURES); 119f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov set.put(pkgName, info); 120f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } catch (NameNotFoundException e) { 121f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov Slog.w(RefactoredBackupManagerService.TAG, "Unknown package " + pkgName + ", skipping"); 122f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 123f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 124f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 125f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 126f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 127f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov private OutputStream emitAesBackupHeader(StringBuilder headerbuf, 128f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov OutputStream ofstream) throws Exception { 129f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // User key will be used to encrypt the master key. 130f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov byte[] newUserSalt = backupManagerService 131f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov .randomBytes(RefactoredBackupManagerService.PBKDF2_SALT_SIZE); 132f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov SecretKey userKey = backupManagerService 133f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov .buildPasswordKey(RefactoredBackupManagerService.PBKDF_CURRENT, mEncryptPassword, newUserSalt, 134f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov RefactoredBackupManagerService.PBKDF2_HASH_ROUNDS); 135f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 136f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // the master key is random for each backup 137f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov byte[] masterPw = new byte[256 / 8]; 138f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov backupManagerService.mRng.nextBytes(masterPw); 139f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov byte[] checksumSalt = backupManagerService 140f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov .randomBytes(RefactoredBackupManagerService.PBKDF2_SALT_SIZE); 141f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 142f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // primary encryption of the datastream with the random key 143f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding"); 144f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov SecretKeySpec masterKeySpec = new SecretKeySpec(masterPw, "AES"); 145f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov c.init(Cipher.ENCRYPT_MODE, masterKeySpec); 146f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov OutputStream finalOutput = new CipherOutputStream(ofstream, c); 147f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 148f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // line 4: name of encryption algorithm 149f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov headerbuf.append(RefactoredBackupManagerService.ENCRYPTION_ALGORITHM_NAME); 150f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov headerbuf.append('\n'); 151f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // line 5: user password salt [hex] 152f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov headerbuf.append(backupManagerService.byteArrayToHex(newUserSalt)); 153f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov headerbuf.append('\n'); 154f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // line 6: master key checksum salt [hex] 155f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov headerbuf.append(backupManagerService.byteArrayToHex(checksumSalt)); 156f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov headerbuf.append('\n'); 157f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // line 7: number of PBKDF2 rounds used [decimal] 158f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov headerbuf.append(RefactoredBackupManagerService.PBKDF2_HASH_ROUNDS); 159f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov headerbuf.append('\n'); 160f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 161f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // line 8: IV of the user key [hex] 162f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov Cipher mkC = Cipher.getInstance("AES/CBC/PKCS5Padding"); 163f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov mkC.init(Cipher.ENCRYPT_MODE, userKey); 164f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 165f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov byte[] IV = mkC.getIV(); 166f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov headerbuf.append(backupManagerService.byteArrayToHex(IV)); 167f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov headerbuf.append('\n'); 168f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 169f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // line 9: master IV + key blob, encrypted by the user key [hex]. Blob format: 170f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // [byte] IV length = Niv 171f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // [array of Niv bytes] IV itself 172f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // [byte] master key length = Nmk 173f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // [array of Nmk bytes] master key itself 174f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // [byte] MK checksum hash length = Nck 175f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // [array of Nck bytes] master key checksum hash 176f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // 177f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // The checksum is the (master key + checksum salt), run through the 178f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // stated number of PBKDF2 rounds 179f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov IV = c.getIV(); 180f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov byte[] mk = masterKeySpec.getEncoded(); 181f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov byte[] checksum = backupManagerService 182f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov .makeKeyChecksum(RefactoredBackupManagerService.PBKDF_CURRENT, masterKeySpec.getEncoded(), 183f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov checksumSalt, RefactoredBackupManagerService.PBKDF2_HASH_ROUNDS); 184f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 185f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov ByteArrayOutputStream blob = new ByteArrayOutputStream(IV.length + mk.length 186f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov + checksum.length + 3); 187f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov DataOutputStream mkOut = new DataOutputStream(blob); 188f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov mkOut.writeByte(IV.length); 189f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov mkOut.write(IV); 190f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov mkOut.writeByte(mk.length); 191f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov mkOut.write(mk); 192f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov mkOut.writeByte(checksum.length); 193f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov mkOut.write(checksum); 194f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov mkOut.flush(); 195f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov byte[] encryptedMk = mkC.doFinal(blob.toByteArray()); 196f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov headerbuf.append(backupManagerService.byteArrayToHex(encryptedMk)); 197f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov headerbuf.append('\n'); 198f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 199f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov return finalOutput; 200f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 201f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 202f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov private void finalizeBackup(OutputStream out) { 203f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov try { 204f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // A standard 'tar' EOF sequence: two 512-byte blocks of all zeroes. 205f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov byte[] eof = new byte[512 * 2]; // newly allocated == zero filled 206f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov out.write(eof); 207f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } catch (IOException e) { 208f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov Slog.w(RefactoredBackupManagerService.TAG, "Error attempting to finalize backup stream"); 209f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 210f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 211f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 212f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov @Override 213f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov public void run() { 214f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov String includeKeyValue = mKeyValue ? ", including key-value backups" : ""; 215f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov Slog.i(RefactoredBackupManagerService.TAG, "--- Performing adb backup" + includeKeyValue + " ---"); 216f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 217f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov TreeMap<String, PackageInfo> packagesToBackup = new TreeMap<>(); 218f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov FullBackupObbConnection obbConnection = new FullBackupObbConnection( 219f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov backupManagerService); 220f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov obbConnection.establish(); // we'll want this later 221f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 222f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov sendStartBackup(); 223f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 224f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // doAllApps supersedes the package set if any 225f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov if (mAllApps) { 226f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov List<PackageInfo> allPackages = backupManagerService.mPackageManager.getInstalledPackages( 227f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov PackageManager.GET_SIGNATURES); 228f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov for (int i = 0; i < allPackages.size(); i++) { 229f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov PackageInfo pkg = allPackages.get(i); 230f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // Exclude system apps if we've been asked to do so 231f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov if (mIncludeSystem == true 232f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov || ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0)) { 233f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov packagesToBackup.put(pkg.packageName, pkg); 234f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 235f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 236f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 237f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 238f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // If we're doing widget state as well, ensure that we have all the involved 239f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // host & provider packages in the set 240f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov if (mDoWidgets) { 241f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // TODO: http://b/22388012 242f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov List<String> pkgs = 243f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov AppWidgetBackupBridge.getWidgetParticipants(UserHandle.USER_SYSTEM); 244f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov if (pkgs != null) { 245f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov if (RefactoredBackupManagerService.MORE_DEBUG) { 246f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov Slog.i(RefactoredBackupManagerService.TAG, "Adding widget participants to backup set:"); 247f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov StringBuilder sb = new StringBuilder(128); 248f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov sb.append(" "); 249f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov for (String s : pkgs) { 250f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov sb.append(' '); 251f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov sb.append(s); 252f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 253f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov Slog.i(RefactoredBackupManagerService.TAG, sb.toString()); 254f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 255f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov addPackagesToSet(packagesToBackup, pkgs); 256f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 257f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 258f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 259f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // Now process the command line argument packages, if any. Note that explicitly- 260f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // named system-partition packages will be included even if includeSystem was 261f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // set to false. 262f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov if (mPackages != null) { 263f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov addPackagesToSet(packagesToBackup, mPackages); 264f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 265f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 266f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // Now we cull any inapplicable / inappropriate packages from the set. This 267f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // includes the special shared-storage agent package; we handle that one 268f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // explicitly at the end of the backup pass. Packages supporting key-value backup are 269f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // added to their own queue, and handled after packages supporting fullbackup. 270f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov ArrayList<PackageInfo> keyValueBackupQueue = new ArrayList<>(); 271f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov Iterator<Entry<String, PackageInfo>> iter = packagesToBackup.entrySet().iterator(); 272f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov while (iter.hasNext()) { 273f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov PackageInfo pkg = iter.next().getValue(); 274f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov if (!RefactoredBackupManagerService.appIsEligibleForBackup(pkg.applicationInfo) 275f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov || RefactoredBackupManagerService.appIsStopped(pkg.applicationInfo)) { 276f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov iter.remove(); 277f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov if (RefactoredBackupManagerService.DEBUG) { 278f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov Slog.i(RefactoredBackupManagerService.TAG, "Package " + pkg.packageName 279f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov + " is not eligible for backup, removing."); 280f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 281f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } else if (RefactoredBackupManagerService.appIsKeyValueOnly(pkg)) { 282f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov iter.remove(); 283f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov if (RefactoredBackupManagerService.DEBUG) { 284f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov Slog.i(RefactoredBackupManagerService.TAG, "Package " + pkg.packageName 285f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov + " is key-value."); 286f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 287f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov keyValueBackupQueue.add(pkg); 288f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 289f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 290f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 291f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // flatten the set of packages now so we can explicitly control the ordering 292f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov ArrayList<PackageInfo> backupQueue = 293f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov new ArrayList<>(packagesToBackup.values()); 294f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov FileOutputStream ofstream = new FileOutputStream(mOutputFile.getFileDescriptor()); 295f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov OutputStream out = null; 296f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 297f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov PackageInfo pkg = null; 298f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov try { 299f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov boolean encrypting = (mEncryptPassword != null && mEncryptPassword.length() > 0); 300f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 301f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // Only allow encrypted backups of encrypted devices 302f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov if (backupManagerService.deviceIsEncrypted() && !encrypting) { 303f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov Slog.e(RefactoredBackupManagerService.TAG, "Unencrypted backup of encrypted device; aborting"); 304f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov return; 305f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 306f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 307f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov OutputStream finalOutput = ofstream; 308f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 309f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // Verify that the given password matches the currently-active 310f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // backup password, if any 311f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov if (!backupManagerService.backupPasswordMatches(mCurrentPassword)) { 312f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov if (RefactoredBackupManagerService.DEBUG) { 313f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov Slog.w(RefactoredBackupManagerService.TAG, "Backup password mismatch; aborting"); 314f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 315f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov return; 316f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 317f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 318f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // Write the global file header. All strings are UTF-8 encoded; lines end 319f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // with a '\n' byte. Actual backup data begins immediately following the 320f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // final '\n'. 321f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // 322f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // line 1: "ANDROID BACKUP" 323f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // line 2: backup file format version, currently "5" 324f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // line 3: compressed? "0" if not compressed, "1" if compressed. 325f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // line 4: name of encryption algorithm [currently only "none" or "AES-256"] 326f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // 327f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // When line 4 is not "none", then additional header data follows: 328f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // 329f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // line 5: user password salt [hex] 330f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // line 6: master key checksum salt [hex] 331f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // line 7: number of PBKDF2 rounds to use (same for user & master) [decimal] 332f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // line 8: IV of the user key [hex] 333f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // line 9: master key blob [hex] 334f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // IV of the master key, master key itself, master key checksum hash 335f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // 336f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // The master key checksum is the master key plus its checksum salt, run through 337f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // 10k rounds of PBKDF2. This is used to verify that the user has supplied the 338f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // correct password for decrypting the archive: the master key decrypted from 339f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // the archive using the user-supplied password is also run through PBKDF2 in 340f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // this way, and if the result does not match the checksum as stored in the 341f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // archive, then we know that the user-supplied password does not match the 342f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // archive's. 343f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov StringBuilder headerbuf = new StringBuilder(1024); 344f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 345f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov headerbuf.append(RefactoredBackupManagerService.BACKUP_FILE_HEADER_MAGIC); 346f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov headerbuf.append(RefactoredBackupManagerService.BACKUP_FILE_VERSION); // integer, no trailing \n 347f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov headerbuf.append(mCompress ? "\n1\n" : "\n0\n"); 348f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 349f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov try { 350f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // Set up the encryption stage if appropriate, and emit the correct header 351f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov if (encrypting) { 352f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov finalOutput = emitAesBackupHeader(headerbuf, finalOutput); 353f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } else { 354f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov headerbuf.append("none\n"); 355f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 356f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 357f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov byte[] header = headerbuf.toString().getBytes("UTF-8"); 358f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov ofstream.write(header); 359f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 360f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // Set up the compression stage feeding into the encryption stage (if any) 361f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov if (mCompress) { 362f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION); 363f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov finalOutput = new DeflaterOutputStream(finalOutput, deflater, true); 364f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 365f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 366f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov out = finalOutput; 367f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } catch (Exception e) { 368f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // Should never happen! 369f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov Slog.e(RefactoredBackupManagerService.TAG, "Unable to emit archive header", e); 370f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov return; 371f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 372f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 373f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // Shared storage if requested 374f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov if (mIncludeShared) { 375f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov try { 376f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov pkg = backupManagerService.mPackageManager.getPackageInfo( 377f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov RefactoredBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE, 0); 378f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov backupQueue.add(pkg); 379f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } catch (NameNotFoundException e) { 380f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov Slog.e(RefactoredBackupManagerService.TAG, "Unable to find shared-storage backup handler"); 381f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 382f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 383f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 384f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // Now actually run the constructed backup sequence for full backup 385f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov int N = backupQueue.size(); 386f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov for (int i = 0; i < N; i++) { 387f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov pkg = backupQueue.get(i); 388f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov if (RefactoredBackupManagerService.DEBUG) { 389f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov Slog.i(RefactoredBackupManagerService.TAG, 390f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov "--- Performing full backup for package " + pkg.packageName 391f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov + " ---"); 392f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 393f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov final boolean isSharedStorage = 394f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov pkg.packageName.equals( 395f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov RefactoredBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE); 396f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 397f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov mBackupEngine = new FullBackupEngine(backupManagerService, out, 398f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov null, pkg, mIncludeApks, this, Long.MAX_VALUE, mCurrentOpToken); 399f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov sendOnBackupPackage(isSharedStorage ? "Shared storage" : pkg.packageName); 400f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 401f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // Don't need to check preflight result as there is no preflight hook. 402f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov mCurrentTarget = pkg; 403f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov mBackupEngine.backupOnePackage(); 404f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 405f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // after the app's agent runs to handle its private filesystem 406f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // contents, back up any OBB content it has on its behalf. 407f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov if (mIncludeObbs) { 408f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov boolean obbOkay = obbConnection.backupObbs(pkg, out); 409f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov if (!obbOkay) { 410f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov throw new RuntimeException("Failure writing OBB stack for " + pkg); 411f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 412f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 413f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 414f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // And for key-value backup if enabled 415f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov if (mKeyValue) { 416f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov for (PackageInfo keyValuePackage : keyValueBackupQueue) { 417f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov if (RefactoredBackupManagerService.DEBUG) { 418f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov Slog.i(RefactoredBackupManagerService.TAG, "--- Performing key-value backup for package " 419f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov + keyValuePackage.packageName + " ---"); 420f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 421f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov KeyValueAdbBackupEngine kvBackupEngine = 422f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov new KeyValueAdbBackupEngine(out, keyValuePackage, 423f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov backupManagerService, 424f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov backupManagerService.mPackageManager, backupManagerService.mBaseStateDir, backupManagerService.mDataDir); 425f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov sendOnBackupPackage(keyValuePackage.packageName); 426f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov kvBackupEngine.backupOnePackage(); 427f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 428f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 429f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 430f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // Done! 431f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov finalizeBackup(out); 432f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } catch (RemoteException e) { 433f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov Slog.e(RefactoredBackupManagerService.TAG, "App died during full backup"); 434f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } catch (Exception e) { 435f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov Slog.e(RefactoredBackupManagerService.TAG, "Internal exception during full backup", e); 436f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } finally { 437f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov try { 438f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov if (out != null) { 439f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov out.flush(); 440f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov out.close(); 441f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 442f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov mOutputFile.close(); 443f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } catch (IOException e) { 444f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov /* nothing we can do about this */ 445f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 446f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov synchronized (mLatch) { 447f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov mLatch.set(true); 448f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov mLatch.notifyAll(); 449f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 450f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov sendEndBackup(); 451f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov obbConnection.tearDown(); 452f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov if (RefactoredBackupManagerService.DEBUG) { 453f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov Slog.d(RefactoredBackupManagerService.TAG, "Full backup pass complete."); 454f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 455f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov backupManagerService.mWakelock.release(); 456f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 457f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 458f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 459f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // BackupRestoreTask methods, used for timeout handling 460f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov @Override 461f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov public void execute() { 462f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // Unused 463f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 464f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 465f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov @Override 466f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov public void operationComplete(long result) { 467f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov // Unused 468f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 469f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov 470f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov @Override 471f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov public void handleCancel(boolean cancelAll) { 472f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov final PackageInfo target = mCurrentTarget; 473f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov if (RefactoredBackupManagerService.DEBUG) { 474f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov Slog.w(RefactoredBackupManagerService.TAG, "adb backup cancel of " + target); 475f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 476f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov if (target != null) { 477f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov backupManagerService.tearDownAgentAndKill(mCurrentTarget.applicationInfo); 478f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 479f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov backupManagerService.removeOperation(mCurrentOpToken); 480f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov } 481f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov} 482