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