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.MORE_DEBUG;
20import static com.android.server.backup.RefactoredBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE;
21import static com.android.server.backup.RefactoredBackupManagerService.TAG;
22
23import android.content.pm.ApplicationInfo;
24import android.content.pm.PackageInfo;
25import android.content.pm.Signature;
26import android.os.Process;
27import android.util.Slog;
28
29import com.android.internal.util.ArrayUtils;
30
31/**
32 * Utility methods wrapping operations on ApplicationInfo and PackageInfo.
33 */
34public class AppBackupUtils {
35    /**
36     * Returns whether app is eligible for backup.
37     *
38     * High level policy: apps are generally ineligible for backup if certain conditions apply. The
39     * conditions are:
40     *
41     * <ol>
42     *     <li>their manifest states android:allowBackup="false"
43     *     <li>they run as a system-level uid but do not supply their own backup agent
44     *     <li>it is the special shared-storage backup package used for 'adb backup'
45     * </ol>
46     */
47    public static boolean appIsEligibleForBackup(ApplicationInfo app) {
48        // 1. their manifest states android:allowBackup="false"
49        if ((app.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) {
50            return false;
51        }
52
53        // 2. they run as a system-level uid but do not supply their own backup agent
54        if ((app.uid < Process.FIRST_APPLICATION_UID) && (app.backupAgentName == null)) {
55            return false;
56        }
57
58        // 3. it is the special shared-storage backup package used for 'adb backup'
59        if (app.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE)) {
60            return false;
61        }
62
63        return true;
64    }
65
66    /**
67     * Checks if the app is in a stopped state, that means it won't receive broadcasts.
68     */
69    public static boolean appIsStopped(ApplicationInfo app) {
70        return ((app.flags & ApplicationInfo.FLAG_STOPPED) != 0);
71    }
72
73    /**
74     * Returns whether the app can get full backup. Does *not* check overall backup eligibility
75     * policy!
76     */
77    public static boolean appGetsFullBackup(PackageInfo pkg) {
78        if (pkg.applicationInfo.backupAgentName != null) {
79            // If it has an agent, it gets full backups only if it says so
80            return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_FULL_BACKUP_ONLY) != 0;
81        }
82
83        // No agent or fullBackupOnly="true" means we do indeed perform full-data backups for it
84        return true;
85    }
86
87    /**
88     * Returns whether the app is only capable of doing key/value. We say it's not if it allows full
89     * backup, and it is otherwise.
90     */
91    public static boolean appIsKeyValueOnly(PackageInfo pkg) {
92        return !appGetsFullBackup(pkg);
93    }
94
95    /**
96     * Returns whether the signatures stored {@param storedSigs}, coming from the source apk, match
97     * the signatures of the apk installed on the device, the target apk. If the target resides in
98     * the system partition we return true. Otherwise it's considered a match if both conditions
99     * hold:
100     *
101     * <ul>
102     *   <li>Source and target have at least one signature each
103     *   <li>Target contains all signatures in source
104     * </ul>
105     *
106     * Note that if {@param target} is null we return false.
107     */
108    public static boolean signaturesMatch(Signature[] storedSigs, PackageInfo target) {
109        if (target == null) {
110            return false;
111        }
112
113        // If the target resides on the system partition, we allow it to restore
114        // data from the like-named package in a restore set even if the signatures
115        // do not match.  (Unlike general applications, those flashed to the system
116        // partition will be signed with the device's platform certificate, so on
117        // different phones the same system app will have different signatures.)
118        if ((target.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
119            if (MORE_DEBUG) {
120                Slog.v(TAG, "System app " + target.packageName + " - skipping sig check");
121            }
122            return true;
123        }
124
125        Signature[] deviceSigs = target.signatures;
126        if (MORE_DEBUG) {
127            Slog.v(TAG, "signaturesMatch(): stored=" + storedSigs + " device=" + deviceSigs);
128        }
129
130        // Don't allow unsigned apps on either end
131        if (ArrayUtils.isEmpty(storedSigs) || ArrayUtils.isEmpty(deviceSigs)) {
132            return false;
133        }
134
135        // Signatures can be added over time, so the target-device apk needs to contain all the
136        // source-device apk signatures, but not necessarily the other way around.
137        int nStored = storedSigs.length;
138        int nDevice = deviceSigs.length;
139
140        for (int i = 0; i < nStored; i++) {
141            boolean match = false;
142            for (int j = 0; j < nDevice; j++) {
143                if (storedSigs[i].equals(deviceSigs[j])) {
144                    match = true;
145                    break;
146                }
147            }
148            if (!match) {
149                return false;
150            }
151        }
152        return true;
153    }
154}
155