blob: 8ab49370bcb2e9c9cd29ec4bdee7e41200d628ee [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.commands.monkey;
import android.Manifest;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PermissionInfo;
import android.os.Build;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
/**
* Utility class that encapsulates runtime permission related methods for monkey
*
*/
public class MonkeyPermissionUtil {
private static final String PERMISSION_PREFIX = "android.permission.";
private static final String PERMISSION_GROUP_PREFIX = "android.permission-group.";
// from com.android.packageinstaller.permission.utils
private static final String[] MODERN_PERMISSION_GROUPS = {
Manifest.permission_group.CALENDAR, Manifest.permission_group.CAMERA,
Manifest.permission_group.CONTACTS, Manifest.permission_group.LOCATION,
Manifest.permission_group.SENSORS, Manifest.permission_group.SMS,
Manifest.permission_group.PHONE, Manifest.permission_group.MICROPHONE,
Manifest.permission_group.STORAGE
};
// from com.android.packageinstaller.permission.utils
private static boolean isModernPermissionGroup(String name) {
for (String modernGroup : MODERN_PERMISSION_GROUPS) {
if (modernGroup.equals(name)) {
return true;
}
}
return false;
}
/**
* actual list of packages to target, with invalid packages excluded, and may optionally include
* system packages
*/
private List<String> mTargetedPackages;
/** if we should target system packages regardless if they are listed */
private boolean mTargetSystemPackages;
private IPackageManager mPm;
/** keep track of runtime permissions requested for each package targeted */
private Map<String, List<PermissionInfo>> mPermissionMap;
public MonkeyPermissionUtil() {
mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
}
public void setTargetSystemPackages(boolean targetSystemPackages) {
mTargetSystemPackages = targetSystemPackages;
}
/**
* Decide if a package should be targeted by permission monkey
* @param info
* @return
*/
private boolean shouldTargetPackage(PackageInfo info) {
// target if permitted by white listing / black listing rules
if (MonkeyUtils.getPackageFilter().checkEnteringPackage(info.packageName)) {
return true;
}
if (mTargetSystemPackages
// not explicitly black listed
&& !MonkeyUtils.getPackageFilter().isPackageInvalid(info.packageName)
// is a system app
&& (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
return true;
}
return false;
}
private boolean shouldTargetPermission(String pkg, PermissionInfo pi) throws RemoteException {
int flags = mPm.getPermissionFlags(pi.name, pkg, UserHandle.myUserId());
int fixedPermFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
| PackageManager.FLAG_PERMISSION_POLICY_FIXED;
return pi.group != null && pi.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS
&& ((flags & fixedPermFlags) == 0)
&& isModernPermissionGroup(pi.group);
}
public boolean populatePermissionsMapping() {
mPermissionMap = new HashMap<>();
try {
List<?> pkgInfos = mPm.getInstalledPackages(
PackageManager.GET_PERMISSIONS, UserHandle.myUserId()).getList();
for (Object o : pkgInfos) {
PackageInfo info = (PackageInfo)o;
if (!shouldTargetPackage(info)) {
continue;
}
List<PermissionInfo> permissions = new ArrayList<>();
if (info.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1) {
// skip apps targetting lower API level
continue;
}
if (info.requestedPermissions == null) {
continue;
}
for (String perm : info.requestedPermissions) {
PermissionInfo pi = mPm.getPermissionInfo(perm, 0);
if (pi != null && shouldTargetPermission(info.packageName, pi)) {
permissions.add(pi);
}
}
if (!permissions.isEmpty()) {
mPermissionMap.put(info.packageName, permissions);
}
}
} catch (RemoteException re) {
System.err.println("** Failed talking with package manager!");
return false;
}
if (!mPermissionMap.isEmpty()) {
mTargetedPackages = new ArrayList<>(mPermissionMap.keySet());
}
return true;
}
public void dump() {
System.out.println("// Targeted packages and permissions:");
for (Map.Entry<String, List<PermissionInfo>> e : mPermissionMap.entrySet()) {
System.out.println(String.format("// + Using %s", e.getKey()));
for (PermissionInfo pi : e.getValue()) {
String name = pi.name;
if (name != null) {
if (name.startsWith(PERMISSION_PREFIX)) {
name = name.substring(PERMISSION_PREFIX.length());
}
}
String group = pi.group;
if (group != null) {
if (group.startsWith(PERMISSION_GROUP_PREFIX)) {
group = group.substring(PERMISSION_GROUP_PREFIX.length());
}
}
System.out.println(String.format("// Permission: %s [%s]", name, group));
}
}
}
public MonkeyPermissionEvent generateRandomPermissionEvent(Random random) {
String pkg = mTargetedPackages.get(random.nextInt(mTargetedPackages.size()));
List<PermissionInfo> infos = mPermissionMap.get(pkg);
return new MonkeyPermissionEvent(pkg, infos.get(random.nextInt(infos.size())));
}
}