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 
17 package com.android.server.pm.permission;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.content.Context;
22 import android.content.pm.PackageParser;
23 import android.util.ArrayMap;
24 import android.util.ArraySet;
25 import android.util.Log;
26 
27 import com.android.internal.R;
28 import com.android.internal.annotations.GuardedBy;
29 import com.android.internal.util.XmlUtils;
30 import com.android.server.pm.DumpState;
31 import com.android.server.pm.PackageManagerService;
32 
33 import org.xmlpull.v1.XmlPullParser;
34 import org.xmlpull.v1.XmlPullParserException;
35 import org.xmlpull.v1.XmlSerializer;
36 
37 import java.io.IOException;
38 import java.io.PrintWriter;
39 import java.util.Collection;
40 import java.util.Set;
41 
42 /**
43  * Permissions and other related data. This class is not meant for
44  * direct access outside of the permission package with the sole exception
45  * of package settings. Instead, it should be reference either from the
46  * permission manager or package settings.
47  */
48 public class PermissionSettings {
49 
50     /**
51      * All of the permissions known to the system. The mapping is from permission
52      * name to permission object.
53      */
54     @GuardedBy("mLock")
55     final ArrayMap<String, BasePermission> mPermissions =
56             new ArrayMap<String, BasePermission>();
57 
58     /**
59      * All permission trees known to the system. The mapping is from permission tree
60      * name to permission object.
61      */
62     @GuardedBy("mLock")
63     final ArrayMap<String, BasePermission> mPermissionTrees =
64             new ArrayMap<String, BasePermission>();
65 
66     /**
67      * All permisson groups know to the system. The mapping is from permission group
68      * name to permission group object.
69      */
70     @GuardedBy("mLock")
71     final ArrayMap<String, PackageParser.PermissionGroup> mPermissionGroups =
72             new ArrayMap<String, PackageParser.PermissionGroup>();
73 
74     /**
75      * Set of packages that request a particular app op. The mapping is from permission
76      * name to package names.
77      */
78     @GuardedBy("mLock")
79     final ArrayMap<String, ArraySet<String>> mAppOpPermissionPackages = new ArrayMap<>();
80 
81     private final Object mLock;
82 
PermissionSettings(@onNull Object lock)83     PermissionSettings(@NonNull Object lock) {
84         mLock = lock;
85     }
86 
getPermission(@onNull String permName)87     public @Nullable BasePermission getPermission(@NonNull String permName) {
88         synchronized (mLock) {
89             return getPermissionLocked(permName);
90         }
91     }
92 
addAppOpPackage(String permName, String packageName)93     public void addAppOpPackage(String permName, String packageName) {
94         ArraySet<String> pkgs = mAppOpPermissionPackages.get(permName);
95         if (pkgs == null) {
96             pkgs = new ArraySet<>();
97             mAppOpPermissionPackages.put(permName, pkgs);
98         }
99         pkgs.add(packageName);
100     }
101 
102     /**
103      * Transfers ownership of permissions from one package to another.
104      */
transferPermissions(String origPackageName, String newPackageName)105     public void transferPermissions(String origPackageName, String newPackageName) {
106         synchronized (mLock) {
107             for (int i=0; i<2; i++) {
108                 ArrayMap<String, BasePermission> permissions =
109                         i == 0 ? mPermissionTrees : mPermissions;
110                 for (BasePermission bp : permissions.values()) {
111                     bp.transfer(origPackageName, newPackageName);
112                 }
113             }
114         }
115     }
116 
canPropagatePermissionToInstantApp(String permName)117     public boolean canPropagatePermissionToInstantApp(String permName) {
118         synchronized (mLock) {
119             final BasePermission bp = mPermissions.get(permName);
120             return (bp != null && (bp.isRuntime() || bp.isDevelopment()) && bp.isInstant());
121         }
122     }
123 
readPermissions(XmlPullParser parser)124     public void readPermissions(XmlPullParser parser) throws IOException, XmlPullParserException {
125         synchronized (mLock) {
126             readPermissions(mPermissions, parser);
127         }
128     }
129 
readPermissionTrees(XmlPullParser parser)130     public void readPermissionTrees(XmlPullParser parser)
131             throws IOException, XmlPullParserException {
132         synchronized (mLock) {
133             readPermissions(mPermissionTrees, parser);
134         }
135     }
136 
writePermissions(XmlSerializer serializer)137     public void writePermissions(XmlSerializer serializer) throws IOException {
138         synchronized (mLock) {
139             for (BasePermission bp : mPermissions.values()) {
140                 bp.writeLPr(serializer);
141             }
142         }
143     }
144 
writePermissionTrees(XmlSerializer serializer)145     public void writePermissionTrees(XmlSerializer serializer) throws IOException {
146         synchronized (mLock) {
147             for (BasePermission bp : mPermissionTrees.values()) {
148                 bp.writeLPr(serializer);
149             }
150         }
151     }
152 
readPermissions(ArrayMap<String, BasePermission> out, XmlPullParser parser)153     public static void readPermissions(ArrayMap<String, BasePermission> out, XmlPullParser parser)
154             throws IOException, XmlPullParserException {
155         int outerDepth = parser.getDepth();
156         int type;
157         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
158                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
159             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
160                 continue;
161             }
162 
163             if (!BasePermission.readLPw(out, parser)) {
164                 PackageManagerService.reportSettingsProblem(Log.WARN,
165                         "Unknown element reading permissions: " + parser.getName() + " at "
166                                 + parser.getPositionDescription());
167             }
168             XmlUtils.skipCurrentTag(parser);
169         }
170     }
171 
dumpPermissions(PrintWriter pw, String packageName, ArraySet<String> permissionNames, boolean externalStorageEnforced, DumpState dumpState)172     public void dumpPermissions(PrintWriter pw, String packageName,
173             ArraySet<String> permissionNames, boolean externalStorageEnforced,
174             DumpState dumpState) {
175         synchronized (mLock) {
176             boolean printedSomething = false;
177             for (BasePermission bp : mPermissions.values()) {
178                 printedSomething = bp.dumpPermissionsLPr(pw, packageName, permissionNames,
179                         externalStorageEnforced, printedSomething, dumpState);
180             }
181             if (packageName == null && permissionNames == null) {
182                 for (int iperm = 0; iperm<mAppOpPermissionPackages.size(); iperm++) {
183                     if (iperm == 0) {
184                         if (dumpState.onTitlePrinted())
185                             pw.println();
186                         pw.println("AppOp Permissions:");
187                     }
188                     pw.print("  AppOp Permission ");
189                     pw.print(mAppOpPermissionPackages.keyAt(iperm));
190                     pw.println(":");
191                     ArraySet<String> pkgs = mAppOpPermissionPackages.valueAt(iperm);
192                     for (int ipkg=0; ipkg<pkgs.size(); ipkg++) {
193                         pw.print("    "); pw.println(pkgs.valueAt(ipkg));
194                     }
195                 }
196             }
197         }
198     }
199 
200     @GuardedBy("mLock")
getPermissionLocked(@onNull String permName)201     @Nullable BasePermission getPermissionLocked(@NonNull String permName) {
202         return mPermissions.get(permName);
203     }
204 
205     @GuardedBy("mLock")
getPermissionTreeLocked(@onNull String permName)206     @Nullable BasePermission getPermissionTreeLocked(@NonNull String permName) {
207         return mPermissionTrees.get(permName);
208     }
209 
210     @GuardedBy("mLock")
putPermissionLocked(@onNull String permName, @NonNull BasePermission permission)211     void putPermissionLocked(@NonNull String permName, @NonNull BasePermission permission) {
212         mPermissions.put(permName, permission);
213     }
214 
215     @GuardedBy("mLock")
putPermissionTreeLocked(@onNull String permName, @NonNull BasePermission permission)216     void putPermissionTreeLocked(@NonNull String permName, @NonNull BasePermission permission) {
217         mPermissionTrees.put(permName, permission);
218     }
219 
220     @GuardedBy("mLock")
removePermissionLocked(@onNull String permName)221     void removePermissionLocked(@NonNull String permName) {
222         mPermissions.remove(permName);
223     }
224 
225     @GuardedBy("mLock")
removePermissionTreeLocked(@onNull String permName)226     void removePermissionTreeLocked(@NonNull String permName) {
227         mPermissionTrees.remove(permName);
228     }
229 
230     @GuardedBy("mLock")
getAllPermissionsLocked()231     @NonNull Collection<BasePermission> getAllPermissionsLocked() {
232         return mPermissions.values();
233     }
234 
235     @GuardedBy("mLock")
getAllPermissionTreesLocked()236     @NonNull Collection<BasePermission> getAllPermissionTreesLocked() {
237         return mPermissionTrees.values();
238     }
239 
240     /**
241      * Returns the permission tree for the given permission.
242      * @throws SecurityException If the calling UID is not allowed to add permissions to the
243      * found permission tree.
244      */
enforcePermissionTree(@onNull String permName, int callingUid)245     @Nullable BasePermission enforcePermissionTree(@NonNull String permName, int callingUid) {
246         synchronized (mLock) {
247             return BasePermission.enforcePermissionTree(
248                     mPermissionTrees.values(), permName, callingUid);
249         }
250     }
251 
isPermissionInstant(String permName)252     public boolean isPermissionInstant(String permName) {
253         synchronized (mLock) {
254             final BasePermission bp = mPermissions.get(permName);
255             return (bp != null && bp.isInstant());
256         }
257     }
258 
isPermissionAppOp(String permName)259     boolean isPermissionAppOp(String permName) {
260         synchronized (mLock) {
261             final BasePermission bp = mPermissions.get(permName);
262             return (bp != null && bp.isAppOp());
263         }
264     }
265 
266 }
267