1 /* 2 * Copyright (C) 2015 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.commands.monkey; 18 19 import android.Manifest; 20 import android.content.pm.ApplicationInfo; 21 import android.content.pm.IPackageManager; 22 import android.content.pm.PackageInfo; 23 import android.content.pm.PackageManager; 24 import android.content.pm.PermissionInfo; 25 import android.os.Build; 26 import android.os.RemoteException; 27 import android.os.ServiceManager; 28 import android.os.UserHandle; 29 import android.permission.IPermissionManager; 30 31 import java.util.ArrayList; 32 import java.util.HashMap; 33 import java.util.List; 34 import java.util.Map; 35 import java.util.Random; 36 37 /** 38 * Utility class that encapsulates runtime permission related methods for monkey 39 * 40 */ 41 public class MonkeyPermissionUtil { 42 43 private static final String PERMISSION_PREFIX = "android.permission."; 44 private static final String PERMISSION_GROUP_PREFIX = "android.permission-group."; 45 46 // from com.android.packageinstaller.permission.utils 47 private static final String[] MODERN_PERMISSION_GROUPS = { 48 Manifest.permission_group.CALENDAR, Manifest.permission_group.CAMERA, 49 Manifest.permission_group.CONTACTS, Manifest.permission_group.LOCATION, 50 Manifest.permission_group.SENSORS, Manifest.permission_group.SMS, 51 Manifest.permission_group.PHONE, Manifest.permission_group.MICROPHONE, 52 Manifest.permission_group.STORAGE 53 }; 54 55 // from com.android.packageinstaller.permission.utils isModernPermissionGroup(String name)56 private static boolean isModernPermissionGroup(String name) { 57 for (String modernGroup : MODERN_PERMISSION_GROUPS) { 58 if (modernGroup.equals(name)) { 59 return true; 60 } 61 } 62 return false; 63 } 64 65 /** 66 * actual list of packages to target, with invalid packages excluded, and may optionally include 67 * system packages 68 */ 69 private List<String> mTargetedPackages; 70 /** if we should target system packages regardless if they are listed */ 71 private boolean mTargetSystemPackages; 72 private IPackageManager mPm; 73 private final IPermissionManager mPermManager; 74 75 /** keep track of runtime permissions requested for each package targeted */ 76 private Map<String, List<PermissionInfo>> mPermissionMap; 77 MonkeyPermissionUtil()78 public MonkeyPermissionUtil() { 79 mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package")); 80 mPermManager = 81 IPermissionManager.Stub.asInterface(ServiceManager.getService("permissionmgr")); 82 } 83 setTargetSystemPackages(boolean targetSystemPackages)84 public void setTargetSystemPackages(boolean targetSystemPackages) { 85 mTargetSystemPackages = targetSystemPackages; 86 } 87 88 /** 89 * Decide if a package should be targeted by permission monkey 90 * @param info 91 * @return 92 */ shouldTargetPackage(PackageInfo info)93 private boolean shouldTargetPackage(PackageInfo info) { 94 // target if permitted by white listing / black listing rules 95 if (MonkeyUtils.getPackageFilter().checkEnteringPackage(info.packageName)) { 96 return true; 97 } 98 if (mTargetSystemPackages 99 // not explicitly black listed 100 && !MonkeyUtils.getPackageFilter().isPackageInvalid(info.packageName) 101 // is a system app 102 && (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { 103 return true; 104 } 105 return false; 106 } 107 shouldTargetPermission(String pkg, PermissionInfo pi)108 private boolean shouldTargetPermission(String pkg, PermissionInfo pi) throws RemoteException { 109 int flags = mPermManager.getPermissionFlags(pkg, pi.name, UserHandle.myUserId()); 110 int fixedPermFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED 111 | PackageManager.FLAG_PERMISSION_POLICY_FIXED; 112 return pi.group != null && pi.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS 113 && ((flags & fixedPermFlags) == 0) 114 && isModernPermissionGroup(pi.group); 115 } 116 populatePermissionsMapping()117 public boolean populatePermissionsMapping() { 118 mPermissionMap = new HashMap<>(); 119 try { 120 List<?> pkgInfos = mPm.getInstalledPackages( 121 PackageManager.GET_PERMISSIONS, UserHandle.myUserId()).getList(); 122 for (Object o : pkgInfos) { 123 PackageInfo info = (PackageInfo)o; 124 if (!shouldTargetPackage(info)) { 125 continue; 126 } 127 List<PermissionInfo> permissions = new ArrayList<>(); 128 if (info.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1) { 129 // skip apps targetting lower API level 130 continue; 131 } 132 if (info.requestedPermissions == null) { 133 continue; 134 } 135 for (String perm : info.requestedPermissions) { 136 PermissionInfo pi = mPermManager.getPermissionInfo(perm, "shell", 0); 137 if (pi != null && shouldTargetPermission(info.packageName, pi)) { 138 permissions.add(pi); 139 } 140 } 141 if (!permissions.isEmpty()) { 142 mPermissionMap.put(info.packageName, permissions); 143 } 144 } 145 } catch (RemoteException re) { 146 Logger.err.println("** Failed talking with package manager!"); 147 return false; 148 } 149 if (!mPermissionMap.isEmpty()) { 150 mTargetedPackages = new ArrayList<>(mPermissionMap.keySet()); 151 } 152 return true; 153 } 154 dump()155 public void dump() { 156 Logger.out.println("// Targeted packages and permissions:"); 157 for (Map.Entry<String, List<PermissionInfo>> e : mPermissionMap.entrySet()) { 158 Logger.out.println(String.format("// + Using %s", e.getKey())); 159 for (PermissionInfo pi : e.getValue()) { 160 String name = pi.name; 161 if (name != null) { 162 if (name.startsWith(PERMISSION_PREFIX)) { 163 name = name.substring(PERMISSION_PREFIX.length()); 164 } 165 } 166 String group = pi.group; 167 if (group != null) { 168 if (group.startsWith(PERMISSION_GROUP_PREFIX)) { 169 group = group.substring(PERMISSION_GROUP_PREFIX.length()); 170 } 171 } 172 Logger.out.println(String.format("// Permission: %s [%s]", name, group)); 173 } 174 } 175 } 176 generateRandomPermissionEvent(Random random)177 public MonkeyPermissionEvent generateRandomPermissionEvent(Random random) { 178 String pkg = mTargetedPackages.get(random.nextInt(mTargetedPackages.size())); 179 List<PermissionInfo> infos = mPermissionMap.get(pkg); 180 return new MonkeyPermissionEvent(pkg, infos.get(random.nextInt(infos.size()))); 181 } 182 } 183