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