RestoreUtils.java revision dbe68324801cfd45d0d1116c9da983b8ebe651ae
1/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package com.android.server.backup.utils;
18
19import static com.android.server.backup.RefactoredBackupManagerService.DEBUG;
20import static com.android.server.backup.RefactoredBackupManagerService.TAG;
21
22import android.content.pm.ApplicationInfo;
23import android.content.pm.PackageInfo;
24import android.content.pm.PackageManager;
25import android.content.pm.Signature;
26import android.net.Uri;
27import android.os.Process;
28import android.util.Slog;
29
30import com.android.server.backup.FileMetadata;
31import com.android.server.backup.restore.RestoreDeleteObserver;
32import com.android.server.backup.restore.RestoreInstallObserver;
33import com.android.server.backup.restore.RestorePolicy;
34
35import java.io.File;
36import java.io.FileOutputStream;
37import java.io.IOException;
38import java.io.InputStream;
39import java.util.HashMap;
40
41/**
42 * Utility methods used by {@link com.android.server.backup.restore.PerformAdbRestoreTask} and
43 * {@link com.android.server.backup.restore.FullRestoreEngine}.
44 */
45public class RestoreUtils {
46    /**
47     * Reads apk contents from input stream and installs the apk.
48     *
49     * @param instream - input stream to read apk data from.
50     * @param packageManager - {@link PackageManager} instance.
51     * @param installObserver - {@link RestoreInstallObserver} instance.
52     * @param deleteObserver - {@link RestoreDeleteObserver} instance.
53     * @param manifestSignatures - manifest signatures.
54     * @param packagePolicies - package policies.
55     * @param info - backup file info.
56     * @param installerPackage - installer package.
57     * @param bytesReadListener - listener to be called for counting bytes read.
58     * @param dataDir - directory where to create apk file.
59     * @return true if apk was successfully read and installed and false otherwise.
60     */
61    // TODO: Refactor to get rid of unneeded params.
62    public static boolean installApk(InputStream instream, PackageManager packageManager,
63            RestoreInstallObserver installObserver, RestoreDeleteObserver deleteObserver,
64            HashMap<String, Signature[]> manifestSignatures,
65            HashMap<String, RestorePolicy> packagePolicies,
66            FileMetadata info,
67            String installerPackage, BytesReadListener bytesReadListener,
68            File dataDir) {
69        boolean okay = true;
70
71        if (DEBUG) {
72            Slog.d(TAG, "Installing from backup: " + info.packageName);
73        }
74
75        // The file content is an .apk file.  Copy it out to a staging location and
76        // attempt to install it.
77        File apkFile = new File(dataDir, info.packageName);
78        try {
79            FileOutputStream apkStream = new FileOutputStream(apkFile);
80            byte[] buffer = new byte[32 * 1024];
81            long size = info.size;
82            while (size > 0) {
83                long toRead = (buffer.length < size) ? buffer.length : size;
84                int didRead = instream.read(buffer, 0, (int) toRead);
85                if (didRead >= 0) {
86                    bytesReadListener.onBytesRead(didRead);
87                }
88                apkStream.write(buffer, 0, didRead);
89                size -= didRead;
90            }
91            apkStream.close();
92
93            // make sure the installer can read it
94            apkFile.setReadable(true, false);
95
96            // Now install it
97            Uri packageUri = Uri.fromFile(apkFile);
98            installObserver.reset();
99            // TODO: PackageManager.installPackage() is deprecated, refactor.
100            packageManager.installPackage(packageUri, installObserver,
101                    PackageManager.INSTALL_REPLACE_EXISTING | PackageManager.INSTALL_FROM_ADB,
102                    installerPackage);
103            installObserver.waitForCompletion();
104
105            if (installObserver.getResult() != PackageManager.INSTALL_SUCCEEDED) {
106                // The only time we continue to accept install of data even if the
107                // apk install failed is if we had already determined that we could
108                // accept the data regardless.
109                if (packagePolicies.get(info.packageName) != RestorePolicy.ACCEPT) {
110                    okay = false;
111                }
112            } else {
113                // Okay, the install succeeded.  Make sure it was the right app.
114                boolean uninstall = false;
115                if (!installObserver.getPackageName().equals(info.packageName)) {
116                    Slog.w(TAG, "Restore stream claimed to include apk for "
117                            + info.packageName + " but apk was really "
118                            + installObserver.getPackageName());
119                    // delete the package we just put in place; it might be fraudulent
120                    okay = false;
121                    uninstall = true;
122                } else {
123                    try {
124                        PackageInfo pkg = packageManager.getPackageInfo(
125                                info.packageName,
126                                PackageManager.GET_SIGNATURES);
127                        if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP)
128                                == 0) {
129                            Slog.w(TAG, "Restore stream contains apk of package "
130                                    + info.packageName
131                                    + " but it disallows backup/restore");
132                            okay = false;
133                        } else {
134                            // So far so good -- do the signatures match the manifest?
135                            Signature[] sigs = manifestSignatures.get(info.packageName);
136                            if (AppBackupUtils.signaturesMatch(sigs, pkg)) {
137                                // If this is a system-uid app without a declared backup agent,
138                                // don't restore any of the file data.
139                                if ((pkg.applicationInfo.uid < Process.FIRST_APPLICATION_UID)
140                                        && (pkg.applicationInfo.backupAgentName == null)) {
141                                    Slog.w(TAG, "Installed app " + info.packageName
142                                            + " has restricted uid and no agent");
143                                    okay = false;
144                                }
145                            } else {
146                                Slog.w(TAG, "Installed app " + info.packageName
147                                        + " signatures do not match restore manifest");
148                                okay = false;
149                                uninstall = true;
150                            }
151                        }
152                    } catch (PackageManager.NameNotFoundException e) {
153                        Slog.w(TAG, "Install of package " + info.packageName
154                                + " succeeded but now not found");
155                        okay = false;
156                    }
157                }
158
159                // If we're not okay at this point, we need to delete the package
160                // that we just installed.
161                if (uninstall) {
162                    deleteObserver.reset();
163                    packageManager.deletePackage(
164                            installObserver.getPackageName(),
165                            deleteObserver, 0);
166                    deleteObserver.waitForCompletion();
167                }
168            }
169        } catch (IOException e) {
170            Slog.e(TAG, "Unable to transcribe restored apk for install");
171            okay = false;
172        } finally {
173            apkFile.delete();
174        }
175
176        return okay;
177    }
178}
179