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