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 
17 package com.android.server.pm;
18 
19 import android.annotation.Nullable;
20 import android.annotation.UserIdInt;
21 import android.content.Context;
22 import android.os.UserHandle;
23 import android.util.ArrayMap;
24 import android.util.ArraySet;
25 import android.util.SparseArray;
26 
27 import com.android.internal.R;
28 import com.android.internal.annotations.GuardedBy;
29 
30 import java.util.List;
31 import java.util.Set;
32 
33 /**
34  * Manages package names that need special protection.
35  *
36  * TODO: This class should persist the information by itself, and also keeps track of device admin
37  * packages for all users.  Then PMS.isPackageDeviceAdmin() should use it instead of talking
38  * to DPMS.
39  */
40 public class ProtectedPackages {
41     @UserIdInt
42     @GuardedBy("this")
43     private int mDeviceOwnerUserId;
44 
45     @Nullable
46     @GuardedBy("this")
47     private String mDeviceOwnerPackage;
48 
49     @Nullable
50     @GuardedBy("this")
51     private SparseArray<String> mProfileOwnerPackages;
52 
53     @Nullable
54     @GuardedBy("this")
55     private final String mDeviceProvisioningPackage;
56 
57     @Nullable
58     @GuardedBy("this")
59     private final ArrayMap<String, Set<String>> mDeviceOwnerProtectedPackages = new ArrayMap<>();
60 
61     private final Context mContext;
62 
ProtectedPackages(Context context)63     public ProtectedPackages(Context context) {
64         mContext = context;
65         mDeviceProvisioningPackage = mContext.getResources().getString(
66                 R.string.config_deviceProvisioningPackage);
67     }
68 
69     /**
70      * Sets the device/profile owner information.
71      */
setDeviceAndProfileOwnerPackages( int deviceOwnerUserId, String deviceOwnerPackage, SparseArray<String> profileOwnerPackages)72     public synchronized void setDeviceAndProfileOwnerPackages(
73             int deviceOwnerUserId, String deviceOwnerPackage,
74             SparseArray<String> profileOwnerPackages) {
75         mDeviceOwnerUserId = deviceOwnerUserId;
76         mDeviceOwnerPackage =
77                 (deviceOwnerUserId == UserHandle.USER_NULL) ? null : deviceOwnerPackage;
78         mProfileOwnerPackages = (profileOwnerPackages == null) ? null
79                 : profileOwnerPackages.clone();
80     }
81 
82     /** Sets the protected packages for the device owner. */
setDeviceOwnerProtectedPackages( String deviceOwnerPackageName, List<String> packageNames)83     public synchronized void setDeviceOwnerProtectedPackages(
84             String deviceOwnerPackageName, List<String> packageNames) {
85         if (packageNames.isEmpty()) {
86             mDeviceOwnerProtectedPackages.remove(deviceOwnerPackageName);
87         } else {
88             mDeviceOwnerProtectedPackages.put(deviceOwnerPackageName, new ArraySet<>(packageNames));
89         }
90     }
91 
hasDeviceOwnerOrProfileOwner(int userId, String packageName)92     private synchronized boolean hasDeviceOwnerOrProfileOwner(int userId, String packageName) {
93         if (packageName == null) {
94             return false;
95         }
96         if (mDeviceOwnerPackage != null) {
97             if ((mDeviceOwnerUserId == userId)
98                     && (packageName.equals(mDeviceOwnerPackage))) {
99                 return true;
100             }
101         }
102         if (mProfileOwnerPackages != null) {
103             if (packageName.equals(mProfileOwnerPackages.get(userId))) {
104                 return true;
105             }
106         }
107         return false;
108     }
109 
getDeviceOwnerOrProfileOwnerPackage(int userId)110     public synchronized String getDeviceOwnerOrProfileOwnerPackage(int userId) {
111         if (mDeviceOwnerUserId == userId) {
112             return mDeviceOwnerPackage;
113         }
114         if (mProfileOwnerPackages == null) {
115             return null;
116         }
117         return mProfileOwnerPackages.get(userId);
118     }
119 
120     /**
121      * Returns {@code true} if a given package is protected. Otherwise, returns {@code false}.
122      *
123      * <p>A protected package means that, apart from the package owner, no system or privileged apps
124      * can modify its data or package state.
125      */
isProtectedPackage(String packageName)126     private synchronized boolean isProtectedPackage(String packageName) {
127         return packageName != null && (packageName.equals(mDeviceProvisioningPackage)
128                 || isDeviceOwnerProtectedPackage(packageName));
129     }
130 
131     /** Returns {@code true} if the given package is a protected package set by any device owner. */
isDeviceOwnerProtectedPackage(String packageName)132     private synchronized boolean isDeviceOwnerProtectedPackage(String packageName) {
133         for (Set<String> protectedPackages : mDeviceOwnerProtectedPackages.values()) {
134             if (protectedPackages.contains(packageName)) {
135                 return true;
136             }
137         }
138         return false;
139     }
140 
141     /**
142      * Returns {@code true} if a given package's state is protected. Otherwise, returns
143      * {@code false}.
144      *
145      * <p>This is not applicable if the caller is the package owner.
146      */
isPackageStateProtected(@serIdInt int userId, String packageName)147     public boolean isPackageStateProtected(@UserIdInt int userId, String packageName) {
148         return hasDeviceOwnerOrProfileOwner(userId, packageName)
149                 || isProtectedPackage(packageName);
150     }
151 
152     /**
153      * Returns {@code true} if a given package's data is protected. Otherwise, returns
154      * {@code false}.
155      */
isPackageDataProtected(@serIdInt int userId, String packageName)156     public boolean isPackageDataProtected(@UserIdInt int userId, String packageName) {
157         return hasDeviceOwnerOrProfileOwner(userId, packageName)
158                 || isProtectedPackage(packageName);
159     }
160 }
161