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