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