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