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