PerformAdbBackupTask.java revision 39194c0582463be17513b9ba82802a703b10c934
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;
20dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikovimport static com.android.server.backup.RefactoredBackupManagerService.BACKUP_FILE_HEADER_MAGIC;
21dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikovimport static com.android.server.backup.RefactoredBackupManagerService.BACKUP_FILE_VERSION;
22dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikovimport static com.android.server.backup.RefactoredBackupManagerService.DEBUG;
23dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikovimport static com.android.server.backup.RefactoredBackupManagerService.MORE_DEBUG;
24dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikovimport static com.android.server.backup.RefactoredBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE;
25dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikovimport static com.android.server.backup.RefactoredBackupManagerService.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;
40f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikovimport com.android.server.backup.RefactoredBackupManagerService;
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
69f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov    private RefactoredBackupManagerService 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
89f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov    public PerformAdbBackupTask(RefactoredBackupManagerService 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,
13221510f0b7571f0689dc48c4f8fdbafea883cbdd0Artem Iglikov                            PackageManager.GET_SIGNATURES);
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) {
2435c90ff0f26dc3e87c70702a1a09b587cb4c82568Michal Karpinski            List<PackageInfo> allPackages = pm.getInstalledPackages(PackageManager.GET_SIGNATURES);
244f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            for (int i = 0; i < allPackages.size(); i++) {
245f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                PackageInfo pkg = allPackages.get(i);
246f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                // Exclude system apps if we've been asked to do so
247f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                if (mIncludeSystem == true
24821510f0b7571f0689dc48c4f8fdbafea883cbdd0Artem Iglikov                        || ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0)) {
249f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                    packagesToBackup.put(pkg.packageName, pkg);
250f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                }
251f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            }
252f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        }
253f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov
254f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        // If we're doing widget state as well, ensure that we have all the involved
255f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        // host & provider packages in the set
256f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        if (mDoWidgets) {
257f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            // TODO: http://b/22388012
258f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            List<String> pkgs =
25921510f0b7571f0689dc48c4f8fdbafea883cbdd0Artem Iglikov                    AppWidgetBackupBridge.getWidgetParticipants(UserHandle.USER_SYSTEM);
260f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            if (pkgs != null) {
261dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikov                if (MORE_DEBUG) {
262dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikov                    Slog.i(TAG, "Adding widget participants to backup set:");
263f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                    StringBuilder sb = new StringBuilder(128);
264f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                    sb.append("   ");
265f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                    for (String s : pkgs) {
266f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                        sb.append(' ');
267f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                        sb.append(s);
268f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                    }
269dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikov                    Slog.i(TAG, sb.toString());
270f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                }
271f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                addPackagesToSet(packagesToBackup, pkgs);
272f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            }
273f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        }
274f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov
275f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        // Now process the command line argument packages, if any. Note that explicitly-
276f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        // named system-partition packages will be included even if includeSystem was
277f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        // set to false.
278f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        if (mPackages != null) {
279f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            addPackagesToSet(packagesToBackup, mPackages);
280f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        }
281f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov
282f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        // Now we cull any inapplicable / inappropriate packages from the set.  This
283f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        // includes the special shared-storage agent package; we handle that one
284f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        // explicitly at the end of the backup pass. Packages supporting key-value backup are
285f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        // added to their own queue, and handled after packages supporting fullbackup.
286f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        ArrayList<PackageInfo> keyValueBackupQueue = new ArrayList<>();
287f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        Iterator<Entry<String, PackageInfo>> iter = packagesToBackup.entrySet().iterator();
288f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        while (iter.hasNext()) {
289f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            PackageInfo pkg = iter.next().getValue();
2905c90ff0f26dc3e87c70702a1a09b587cb4c82568Michal Karpinski            if (!AppBackupUtils.appIsEligibleForBackup(pkg.applicationInfo, pm)
2912c2c856b3a60e96e09261d2513b43acb7ff4b070Artem Iglikov                    || AppBackupUtils.appIsStopped(pkg.applicationInfo)) {
292f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                iter.remove();
293dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikov                if (DEBUG) {
294dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikov                    Slog.i(TAG, "Package " + pkg.packageName
29521510f0b7571f0689dc48c4f8fdbafea883cbdd0Artem Iglikov                            + " is not eligible for backup, removing.");
296f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                }
2972c2c856b3a60e96e09261d2513b43acb7ff4b070Artem Iglikov            } else if (AppBackupUtils.appIsKeyValueOnly(pkg)) {
298f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                iter.remove();
299dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikov                if (DEBUG) {
300dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikov                    Slog.i(TAG, "Package " + pkg.packageName
30121510f0b7571f0689dc48c4f8fdbafea883cbdd0Artem Iglikov                            + " is key-value.");
302f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                }
303f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                keyValueBackupQueue.add(pkg);
304f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            }
305f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        }
306f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov
307f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        // flatten the set of packages now so we can explicitly control the ordering
308f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        ArrayList<PackageInfo> backupQueue =
30921510f0b7571f0689dc48c4f8fdbafea883cbdd0Artem Iglikov                new ArrayList<>(packagesToBackup.values());
310f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        FileOutputStream ofstream = new FileOutputStream(mOutputFile.getFileDescriptor());
311f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        OutputStream out = null;
312f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov
313f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        PackageInfo pkg = null;
314f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        try {
315f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            boolean encrypting = (mEncryptPassword != null && mEncryptPassword.length() > 0);
316f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov
317f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            // Only allow encrypted backups of encrypted devices
318f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            if (backupManagerService.deviceIsEncrypted() && !encrypting) {
319dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikov                Slog.e(TAG, "Unencrypted backup of encrypted device; aborting");
320f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                return;
321f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            }
322f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov
323f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            OutputStream finalOutput = ofstream;
324f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov
325f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            // Verify that the given password matches the currently-active
326f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            // backup password, if any
327f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            if (!backupManagerService.backupPasswordMatches(mCurrentPassword)) {
328dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikov                if (DEBUG) {
329dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikov                    Slog.w(TAG, "Backup password mismatch; aborting");
330f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                }
331f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                return;
332f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            }
333f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov
334f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            // Write the global file header.  All strings are UTF-8 encoded; lines end
335f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            // with a '\n' byte.  Actual backup data begins immediately following the
336f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            // final '\n'.
337f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            //
338f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            // line 1: "ANDROID BACKUP"
339f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            // line 2: backup file format version, currently "5"
340f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            // line 3: compressed?  "0" if not compressed, "1" if compressed.
341f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            // line 4: name of encryption algorithm [currently only "none" or "AES-256"]
342f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            //
343f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            // When line 4 is not "none", then additional header data follows:
344f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            //
345f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            // line 5: user password salt [hex]
346f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            // line 6: master key checksum salt [hex]
347f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            // line 7: number of PBKDF2 rounds to use (same for user & master) [decimal]
348f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            // line 8: IV of the user key [hex]
349f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            // line 9: master key blob [hex]
350f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            //     IV of the master key, master key itself, master key checksum hash
351f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            //
352f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            // The master key checksum is the master key plus its checksum salt, run through
353f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            // 10k rounds of PBKDF2.  This is used to verify that the user has supplied the
354f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            // correct password for decrypting the archive:  the master key decrypted from
355f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            // the archive using the user-supplied password is also run through PBKDF2 in
356f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            // this way, and if the result does not match the checksum as stored in the
357f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            // archive, then we know that the user-supplied password does not match the
358f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            // archive's.
359f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            StringBuilder headerbuf = new StringBuilder(1024);
360f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov
361dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikov            headerbuf.append(BACKUP_FILE_HEADER_MAGIC);
362dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikov            headerbuf.append(BACKUP_FILE_VERSION); // integer, no trailing \n
363f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            headerbuf.append(mCompress ? "\n1\n" : "\n0\n");
364f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov
365f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            try {
366f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                // Set up the encryption stage if appropriate, and emit the correct header
367f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                if (encrypting) {
368f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                    finalOutput = emitAesBackupHeader(headerbuf, finalOutput);
369f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                } else {
370f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                    headerbuf.append("none\n");
371f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                }
372f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov
373f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                byte[] header = headerbuf.toString().getBytes("UTF-8");
374f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                ofstream.write(header);
375f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov
376f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                // Set up the compression stage feeding into the encryption stage (if any)
377f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                if (mCompress) {
378f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                    Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION);
379f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                    finalOutput = new DeflaterOutputStream(finalOutput, deflater, true);
380f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                }
381f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov
382f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                out = finalOutput;
383f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            } catch (Exception e) {
384f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                // Should never happen!
385dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikov                Slog.e(TAG, "Unable to emit archive header", e);
386f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                return;
387f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            }
388f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov
389f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            // Shared storage if requested
390f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            if (mIncludeShared) {
391f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                try {
392d6c00c711000aa70db51f46b48a86c2884e91b15Artem Iglikov                    pkg = backupManagerService.getPackageManager().getPackageInfo(
393dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikov                            SHARED_BACKUP_AGENT_PACKAGE, 0);
394f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                    backupQueue.add(pkg);
395f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                } catch (NameNotFoundException e) {
396dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikov                    Slog.e(TAG, "Unable to find shared-storage backup handler");
397f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                }
398f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            }
399f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov
400f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            // Now actually run the constructed backup sequence for full backup
401f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            int N = backupQueue.size();
402f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            for (int i = 0; i < N; i++) {
403f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                pkg = backupQueue.get(i);
404dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikov                if (DEBUG) {
405dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikov                    Slog.i(TAG, "--- Performing full backup for package " + pkg.packageName
406dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikov                            + " ---");
407f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                }
408f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                final boolean isSharedStorage =
40921510f0b7571f0689dc48c4f8fdbafea883cbdd0Artem Iglikov                        pkg.packageName.equals(
410dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikov                                SHARED_BACKUP_AGENT_PACKAGE);
411f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov
412f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                mBackupEngine = new FullBackupEngine(backupManagerService, out,
41339194c0582463be17513b9ba82802a703b10c934Robert Berry                        null, pkg, mIncludeApks, this, Long.MAX_VALUE,
41439194c0582463be17513b9ba82802a703b10c934Robert Berry                        mCurrentOpToken, /*transportFlags=*/ 0);
415f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                sendOnBackupPackage(isSharedStorage ? "Shared storage" : pkg.packageName);
416f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov
417f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                // Don't need to check preflight result as there is no preflight hook.
418f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                mCurrentTarget = pkg;
419f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                mBackupEngine.backupOnePackage();
420f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov
421f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                // after the app's agent runs to handle its private filesystem
422f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                // contents, back up any OBB content it has on its behalf.
423f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                if (mIncludeObbs) {
424f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                    boolean obbOkay = obbConnection.backupObbs(pkg, out);
425f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                    if (!obbOkay) {
426f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                        throw new RuntimeException("Failure writing OBB stack for " + pkg);
427f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                    }
428f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                }
429f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            }
430f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            // And for key-value backup if enabled
431f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            if (mKeyValue) {
432f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                for (PackageInfo keyValuePackage : keyValueBackupQueue) {
433dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikov                    if (DEBUG) {
434dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikov                        Slog.i(TAG, "--- Performing key-value backup for package "
435dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikov                                + keyValuePackage.packageName + " ---");
436f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                    }
437f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                    KeyValueAdbBackupEngine kvBackupEngine =
43821510f0b7571f0689dc48c4f8fdbafea883cbdd0Artem Iglikov                            new KeyValueAdbBackupEngine(out, keyValuePackage,
43921510f0b7571f0689dc48c4f8fdbafea883cbdd0Artem Iglikov                                    backupManagerService,
440d6c00c711000aa70db51f46b48a86c2884e91b15Artem Iglikov                                    backupManagerService.getPackageManager(),
441d6c00c711000aa70db51f46b48a86c2884e91b15Artem Iglikov                                    backupManagerService.getBaseStateDir(),
442d6c00c711000aa70db51f46b48a86c2884e91b15Artem Iglikov                                    backupManagerService.getDataDir());
443f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                    sendOnBackupPackage(keyValuePackage.packageName);
444f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                    kvBackupEngine.backupOnePackage();
445f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                }
446f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            }
447f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov
448f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            // Done!
449f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            finalizeBackup(out);
450f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        } catch (RemoteException e) {
451dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikov            Slog.e(TAG, "App died during full backup");
452f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        } catch (Exception e) {
453dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikov            Slog.e(TAG, "Internal exception during full backup", e);
454f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        } finally {
455f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            try {
456f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                if (out != null) {
457f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                    out.flush();
458f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                    out.close();
459f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                }
460f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                mOutputFile.close();
461f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            } catch (IOException e) {
4625176c02501054da21d2729339037c66416c09528Bernardo Rufino                Slog.e(TAG, "IO error closing adb backup file: " + e.getMessage());
463f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            }
464f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            synchronized (mLatch) {
465f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                mLatch.set(true);
466f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov                mLatch.notifyAll();
467f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            }
468f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            sendEndBackup();
469f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            obbConnection.tearDown();
470dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikov            if (DEBUG) {
471dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikov                Slog.d(TAG, "Full backup pass complete.");
472f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            }
473d6c00c711000aa70db51f46b48a86c2884e91b15Artem Iglikov            backupManagerService.getWakelock().release();
474f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        }
475f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov    }
476f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov
477f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov    // BackupRestoreTask methods, used for timeout handling
478f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov    @Override
479f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov    public void execute() {
480f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        // Unused
481f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov    }
482f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov
483f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov    @Override
484f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov    public void operationComplete(long result) {
485f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        // Unused
486f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov    }
487f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov
488f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov    @Override
489f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov    public void handleCancel(boolean cancelAll) {
490f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        final PackageInfo target = mCurrentTarget;
491dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikov        if (DEBUG) {
492dbe68324801cfd45d0d1116c9da983b8ebe651aeArtem Iglikov            Slog.w(TAG, "adb backup cancel of " + target);
493f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        }
494f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        if (target != null) {
495f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov            backupManagerService.tearDownAgentAndKill(mCurrentTarget.applicationInfo);
496f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        }
497f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov        backupManagerService.removeOperation(mCurrentOpToken);
498f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov    }
499f251e3509838e3fbc62ccdba9d4cfd0527f67acdArtem Iglikov}
500