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