1/*
2 * Copyright (C) 2016 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.pm;
18
19import android.annotation.Nullable;
20import android.annotation.UserIdInt;
21import android.content.Context;
22import android.os.UserHandle;
23import android.util.SparseArray;
24
25import com.android.internal.R;
26import com.android.internal.annotations.GuardedBy;
27
28/**
29 * Manages package names that need special protection.
30 *
31 * TODO: This class should persist the information by itself, and also keeps track of device admin
32 * packages for all users.  Then PMS.isPackageDeviceAdmin() should use it instead of talking
33 * to DPMS.
34 */
35public class ProtectedPackages {
36    @UserIdInt
37    @GuardedBy("this")
38    private int mDeviceOwnerUserId;
39
40    @Nullable
41    @GuardedBy("this")
42    private String mDeviceOwnerPackage;
43
44    @Nullable
45    @GuardedBy("this")
46    private SparseArray<String> mProfileOwnerPackages;
47
48    @Nullable
49    @GuardedBy("this")
50    private final String mDeviceProvisioningPackage;
51
52    private final Context mContext;
53
54    public ProtectedPackages(Context context) {
55        mContext = context;
56        mDeviceProvisioningPackage = mContext.getResources().getString(
57                R.string.config_deviceProvisioningPackage);
58    }
59
60    /**
61     * Sets the device/profile owner information.
62     */
63    public synchronized void setDeviceAndProfileOwnerPackages(
64            int deviceOwnerUserId, String deviceOwnerPackage,
65            SparseArray<String> profileOwnerPackages) {
66        mDeviceOwnerUserId = deviceOwnerUserId;
67        mDeviceOwnerPackage =
68                (deviceOwnerUserId == UserHandle.USER_NULL) ? null : deviceOwnerPackage;
69        mProfileOwnerPackages = (profileOwnerPackages == null) ? null
70                : profileOwnerPackages.clone();
71    }
72
73    private synchronized boolean hasDeviceOwnerOrProfileOwner(int userId, String packageName) {
74        if (packageName == null) {
75            return false;
76        }
77        if (mDeviceOwnerPackage != null) {
78            if ((mDeviceOwnerUserId == userId)
79                    && (packageName.equals(mDeviceOwnerPackage))) {
80                return true;
81            }
82        }
83        if (mProfileOwnerPackages != null) {
84            if (packageName.equals(mProfileOwnerPackages.get(userId))) {
85                return true;
86            }
87        }
88        return false;
89    }
90
91    /**
92     * Returns {@code true} if a given package is protected. Otherwise, returns {@code false}.
93     *
94     * <p>A protected package means that, apart from the package owner, no system or privileged apps
95     * can modify its data or package state.
96     */
97    private synchronized boolean isProtectedPackage(String packageName) {
98        return packageName != null && packageName.equals(mDeviceProvisioningPackage);
99    }
100
101    /**
102     * Returns {@code true} if a given package's state is protected. Otherwise, returns
103     * {@code false}.
104     *
105     * <p>This is not applicable if the caller is the package owner.
106     */
107    public boolean isPackageStateProtected(@UserIdInt int userId, String packageName) {
108        return hasDeviceOwnerOrProfileOwner(userId, packageName)
109                || isProtectedPackage(packageName);
110    }
111
112    /**
113     * Returns {@code true} if a given package's data is protected. Otherwise, returns
114     * {@code false}.
115     */
116    public boolean isPackageDataProtected(@UserIdInt int userId, String packageName) {
117        return hasDeviceOwnerOrProfileOwner(userId, packageName)
118                || isProtectedPackage(packageName);
119    }
120}
121