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