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