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