teach monkey to flip permissions on apps
1. added a new MonkeyEvent type for permission events 2. added monkey permission utility for randomized permission events generation against targeted packages 3. refactored package whitelist/blacklist into MonkeyUtils class Change-Id: I8f7998d74c3e28d02f5bcd47a0f9cc6167b93c93
This commit is contained in:
@@ -31,15 +31,12 @@ import android.os.RemoteException;
|
|||||||
import android.os.ServiceManager;
|
import android.os.ServiceManager;
|
||||||
import android.os.StrictMode;
|
import android.os.StrictMode;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.os.SystemProperties;
|
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.view.IWindowManager;
|
import android.view.IWindowManager;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.BufferedWriter;
|
import java.io.BufferedWriter;
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.DataInputStream;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
import java.io.FileWriter;
|
import java.io.FileWriter;
|
||||||
@@ -47,12 +44,12 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Application that injects random key events and other actions into the system.
|
* Application that injects random key events and other actions into the system.
|
||||||
@@ -181,12 +178,6 @@ public class Monkey {
|
|||||||
/** Package whitelist file. */
|
/** Package whitelist file. */
|
||||||
private String mPkgWhitelistFile;
|
private String mPkgWhitelistFile;
|
||||||
|
|
||||||
/** Packages we are allowed to run, or empty if no restriction. */
|
|
||||||
private HashSet<String> mValidPackages = new HashSet<String>();
|
|
||||||
|
|
||||||
/** Packages we are not allowed to run. */
|
|
||||||
private HashSet<String> mInvalidPackages = new HashSet<String>();
|
|
||||||
|
|
||||||
/** Categories we are allowed to launch **/
|
/** Categories we are allowed to launch **/
|
||||||
private ArrayList<String> mMainCategories = new ArrayList<String>();
|
private ArrayList<String> mMainCategories = new ArrayList<String>();
|
||||||
|
|
||||||
@@ -251,36 +242,20 @@ public class Monkey {
|
|||||||
|
|
||||||
private MonkeyNetworkMonitor mNetworkMonitor = new MonkeyNetworkMonitor();
|
private MonkeyNetworkMonitor mNetworkMonitor = new MonkeyNetworkMonitor();
|
||||||
|
|
||||||
|
private boolean mPermissionTargetSystem = false;
|
||||||
|
|
||||||
// information on the current activity.
|
// information on the current activity.
|
||||||
public static Intent currentIntent;
|
public static Intent currentIntent;
|
||||||
|
|
||||||
public static String currentPackage;
|
public static String currentPackage;
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether we should run against the givn package.
|
|
||||||
*
|
|
||||||
* @param pkg The package name.
|
|
||||||
* @return Returns true if we should run against pkg.
|
|
||||||
*/
|
|
||||||
private boolean checkEnteringPackage(String pkg) {
|
|
||||||
if (mInvalidPackages.size() > 0) {
|
|
||||||
if (mInvalidPackages.contains(pkg)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (mValidPackages.size() > 0) {
|
|
||||||
if (!mValidPackages.contains(pkg)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Monitor operations happening in the system.
|
* Monitor operations happening in the system.
|
||||||
*/
|
*/
|
||||||
private class ActivityController extends IActivityController.Stub {
|
private class ActivityController extends IActivityController.Stub {
|
||||||
public boolean activityStarting(Intent intent, String pkg) {
|
public boolean activityStarting(Intent intent, String pkg) {
|
||||||
boolean allow = checkEnteringPackage(pkg) || (DEBUG_ALLOW_ANY_STARTS != 0);
|
boolean allow = MonkeyUtils.getPackageFilter().checkEnteringPackage(pkg)
|
||||||
|
|| (DEBUG_ALLOW_ANY_STARTS != 0);
|
||||||
if (mVerbose > 0) {
|
if (mVerbose > 0) {
|
||||||
// StrictMode's disk checks end up catching this on
|
// StrictMode's disk checks end up catching this on
|
||||||
// userdebug/eng builds due to PrintStream going to a
|
// userdebug/eng builds due to PrintStream going to a
|
||||||
@@ -301,7 +276,8 @@ public class Monkey {
|
|||||||
public boolean activityResuming(String pkg) {
|
public boolean activityResuming(String pkg) {
|
||||||
StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
|
StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
|
||||||
System.out.println(" // activityResuming(" + pkg + ")");
|
System.out.println(" // activityResuming(" + pkg + ")");
|
||||||
boolean allow = checkEnteringPackage(pkg) || (DEBUG_ALLOW_ANY_RESTARTS != 0);
|
boolean allow = MonkeyUtils.getPackageFilter().checkEnteringPackage(pkg)
|
||||||
|
|| (DEBUG_ALLOW_ANY_RESTARTS != 0);
|
||||||
if (!allow) {
|
if (!allow) {
|
||||||
if (mVerbose > 0) {
|
if (mVerbose > 0) {
|
||||||
System.out.println(" // " + (allow ? "Allowing" : "Rejecting")
|
System.out.println(" // " + (allow ? "Allowing" : "Rejecting")
|
||||||
@@ -559,18 +535,7 @@ public class Monkey {
|
|||||||
|
|
||||||
if (mVerbose > 0) {
|
if (mVerbose > 0) {
|
||||||
System.out.println(":Monkey: seed=" + mSeed + " count=" + mCount);
|
System.out.println(":Monkey: seed=" + mSeed + " count=" + mCount);
|
||||||
if (mValidPackages.size() > 0) {
|
MonkeyUtils.getPackageFilter().dump();
|
||||||
Iterator<String> it = mValidPackages.iterator();
|
|
||||||
while (it.hasNext()) {
|
|
||||||
System.out.println(":AllowPackage: " + it.next());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (mInvalidPackages.size() > 0) {
|
|
||||||
Iterator<String> it = mInvalidPackages.iterator();
|
|
||||||
while (it.hasNext()) {
|
|
||||||
System.out.println(":DisallowPackage: " + it.next());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (mMainCategories.size() != 0) {
|
if (mMainCategories.size() != 0) {
|
||||||
Iterator<String> it = mMainCategories.iterator();
|
Iterator<String> it = mMainCategories.iterator();
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
@@ -626,7 +591,8 @@ public class Monkey {
|
|||||||
if (mVerbose >= 2) { // check seeding performance
|
if (mVerbose >= 2) { // check seeding performance
|
||||||
System.out.println("// Seeded: " + mSeed);
|
System.out.println("// Seeded: " + mSeed);
|
||||||
}
|
}
|
||||||
mEventSource = new MonkeySourceRandom(mRandom, mMainApps, mThrottle, mRandomizeThrottle);
|
mEventSource = new MonkeySourceRandom(mRandom, mMainApps,
|
||||||
|
mThrottle, mRandomizeThrottle, mPermissionTargetSystem);
|
||||||
mEventSource.setVerbose(mVerbose);
|
mEventSource.setVerbose(mVerbose);
|
||||||
// set any of the factors that has been set
|
// set any of the factors that has been set
|
||||||
for (int i = 0; i < MonkeySourceRandom.FACTORZ_COUNT; i++) {
|
for (int i = 0; i < MonkeySourceRandom.FACTORZ_COUNT; i++) {
|
||||||
@@ -756,11 +722,12 @@ public class Monkey {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
String opt;
|
String opt;
|
||||||
|
Set<String> validPackages = new HashSet<>();
|
||||||
while ((opt = nextOption()) != null) {
|
while ((opt = nextOption()) != null) {
|
||||||
if (opt.equals("-s")) {
|
if (opt.equals("-s")) {
|
||||||
mSeed = nextOptionLong("Seed");
|
mSeed = nextOptionLong("Seed");
|
||||||
} else if (opt.equals("-p")) {
|
} else if (opt.equals("-p")) {
|
||||||
mValidPackages.add(nextOptionData());
|
validPackages.add(nextOptionData());
|
||||||
} else if (opt.equals("-c")) {
|
} else if (opt.equals("-c")) {
|
||||||
mMainCategories.add(nextOptionData());
|
mMainCategories.add(nextOptionData());
|
||||||
} else if (opt.equals("-v")) {
|
} else if (opt.equals("-v")) {
|
||||||
@@ -812,6 +779,9 @@ public class Monkey {
|
|||||||
} else if (opt.equals("--pct-pinchzoom")) {
|
} else if (opt.equals("--pct-pinchzoom")) {
|
||||||
int i = MonkeySourceRandom.FACTOR_PINCHZOOM;
|
int i = MonkeySourceRandom.FACTOR_PINCHZOOM;
|
||||||
mFactors[i] = -nextOptionLong("pinch zoom events percentage");
|
mFactors[i] = -nextOptionLong("pinch zoom events percentage");
|
||||||
|
} else if (opt.equals("--pct-permission")) {
|
||||||
|
int i = MonkeySourceRandom.FACTOR_PERMISSION;
|
||||||
|
mFactors[i] = -nextOptionLong("runtime permission toggle events percentage");
|
||||||
} else if (opt.equals("--pkg-blacklist-file")) {
|
} else if (opt.equals("--pkg-blacklist-file")) {
|
||||||
mPkgBlacklistFile = nextOptionData();
|
mPkgBlacklistFile = nextOptionData();
|
||||||
} else if (opt.equals("--pkg-whitelist-file")) {
|
} else if (opt.equals("--pkg-whitelist-file")) {
|
||||||
@@ -845,6 +815,8 @@ public class Monkey {
|
|||||||
} else if (opt.equals("--periodic-bugreport")){
|
} else if (opt.equals("--periodic-bugreport")){
|
||||||
mGetPeriodicBugreport = true;
|
mGetPeriodicBugreport = true;
|
||||||
mBugreportFrequency = nextOptionLong("Number of iterations");
|
mBugreportFrequency = nextOptionLong("Number of iterations");
|
||||||
|
} else if (opt.equals("--permission-target-system")){
|
||||||
|
mPermissionTargetSystem = true;
|
||||||
} else if (opt.equals("-h")) {
|
} else if (opt.equals("-h")) {
|
||||||
showUsage();
|
showUsage();
|
||||||
return false;
|
return false;
|
||||||
@@ -854,6 +826,7 @@ public class Monkey {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
MonkeyUtils.getPackageFilter().addValidPackages(validPackages);
|
||||||
} catch (RuntimeException ex) {
|
} catch (RuntimeException ex) {
|
||||||
System.err.println("** Error: " + ex.toString());
|
System.err.println("** Error: " + ex.toString());
|
||||||
showUsage();
|
showUsage();
|
||||||
@@ -889,7 +862,7 @@ public class Monkey {
|
|||||||
* @param list The destination list.
|
* @param list The destination list.
|
||||||
* @return Returns false if any error occurs.
|
* @return Returns false if any error occurs.
|
||||||
*/
|
*/
|
||||||
private static boolean loadPackageListFromFile(String fileName, HashSet<String> list) {
|
private static boolean loadPackageListFromFile(String fileName, Set<String> list) {
|
||||||
BufferedReader reader = null;
|
BufferedReader reader = null;
|
||||||
try {
|
try {
|
||||||
reader = new BufferedReader(new FileReader(fileName));
|
reader = new BufferedReader(new FileReader(fileName));
|
||||||
@@ -921,20 +894,24 @@ public class Monkey {
|
|||||||
* @return Returns false if any error occurs.
|
* @return Returns false if any error occurs.
|
||||||
*/
|
*/
|
||||||
private boolean loadPackageLists() {
|
private boolean loadPackageLists() {
|
||||||
if (((mPkgWhitelistFile != null) || (mValidPackages.size() > 0))
|
if (((mPkgWhitelistFile != null) || (MonkeyUtils.getPackageFilter().hasValidPackages()))
|
||||||
&& (mPkgBlacklistFile != null)) {
|
&& (mPkgBlacklistFile != null)) {
|
||||||
System.err.println("** Error: you can not specify a package blacklist "
|
System.err.println("** Error: you can not specify a package blacklist "
|
||||||
+ "together with a whitelist or individual packages (via -p).");
|
+ "together with a whitelist or individual packages (via -p).");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
Set<String> validPackages = new HashSet<>();
|
||||||
if ((mPkgWhitelistFile != null)
|
if ((mPkgWhitelistFile != null)
|
||||||
&& (!loadPackageListFromFile(mPkgWhitelistFile, mValidPackages))) {
|
&& (!loadPackageListFromFile(mPkgWhitelistFile, validPackages))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
MonkeyUtils.getPackageFilter().addValidPackages(validPackages);
|
||||||
|
Set<String> invalidPackages = new HashSet<>();
|
||||||
if ((mPkgBlacklistFile != null)
|
if ((mPkgBlacklistFile != null)
|
||||||
&& (!loadPackageListFromFile(mPkgBlacklistFile, mInvalidPackages))) {
|
&& (!loadPackageListFromFile(mPkgBlacklistFile, invalidPackages))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
MonkeyUtils.getPackageFilter().addInvalidPackages(invalidPackages);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1014,7 +991,7 @@ public class Monkey {
|
|||||||
for (int a = 0; a < NA; a++) {
|
for (int a = 0; a < NA; a++) {
|
||||||
ResolveInfo r = mainApps.get(a);
|
ResolveInfo r = mainApps.get(a);
|
||||||
String packageName = r.activityInfo.applicationInfo.packageName;
|
String packageName = r.activityInfo.applicationInfo.packageName;
|
||||||
if (checkEnteringPackage(packageName)) {
|
if (MonkeyUtils.getPackageFilter().checkEnteringPackage(packageName)) {
|
||||||
if (mVerbose >= 2) { // very verbose
|
if (mVerbose >= 2) { // very verbose
|
||||||
System.out.println("// + Using main activity " + r.activityInfo.name
|
System.out.println("// + Using main activity " + r.activityInfo.name
|
||||||
+ " (from package " + packageName + ")");
|
+ " (from package " + packageName + ")");
|
||||||
@@ -1352,6 +1329,7 @@ public class Monkey {
|
|||||||
usage.append(" [--pct-nav PERCENT] [--pct-majornav PERCENT]\n");
|
usage.append(" [--pct-nav PERCENT] [--pct-majornav PERCENT]\n");
|
||||||
usage.append(" [--pct-appswitch PERCENT] [--pct-flip PERCENT]\n");
|
usage.append(" [--pct-appswitch PERCENT] [--pct-flip PERCENT]\n");
|
||||||
usage.append(" [--pct-anyevent PERCENT] [--pct-pinchzoom PERCENT]\n");
|
usage.append(" [--pct-anyevent PERCENT] [--pct-pinchzoom PERCENT]\n");
|
||||||
|
usage.append(" [--pct-permission PERCENT]\n");
|
||||||
usage.append(" [--pkg-blacklist-file PACKAGE_BLACKLIST_FILE]\n");
|
usage.append(" [--pkg-blacklist-file PACKAGE_BLACKLIST_FILE]\n");
|
||||||
usage.append(" [--pkg-whitelist-file PACKAGE_WHITELIST_FILE]\n");
|
usage.append(" [--pkg-whitelist-file PACKAGE_WHITELIST_FILE]\n");
|
||||||
usage.append(" [--wait-dbg] [--dbg-no-events]\n");
|
usage.append(" [--wait-dbg] [--dbg-no-events]\n");
|
||||||
@@ -1365,6 +1343,7 @@ public class Monkey {
|
|||||||
usage.append(" [--script-log]\n");
|
usage.append(" [--script-log]\n");
|
||||||
usage.append(" [--bugreport]\n");
|
usage.append(" [--bugreport]\n");
|
||||||
usage.append(" [--periodic-bugreport]\n");
|
usage.append(" [--periodic-bugreport]\n");
|
||||||
|
usage.append(" [--permission-target-system]\n");
|
||||||
usage.append(" COUNT\n");
|
usage.append(" COUNT\n");
|
||||||
System.err.println(usage.toString());
|
System.err.println(usage.toString());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,8 @@ public abstract class MonkeyEvent {
|
|||||||
public static final int EVENT_TYPE_ACTIVITY = 4;
|
public static final int EVENT_TYPE_ACTIVITY = 4;
|
||||||
public static final int EVENT_TYPE_FLIP = 5; // Keyboard flip
|
public static final int EVENT_TYPE_FLIP = 5; // Keyboard flip
|
||||||
public static final int EVENT_TYPE_THROTTLE = 6;
|
public static final int EVENT_TYPE_THROTTLE = 6;
|
||||||
public static final int EVENT_TYPE_NOOP = 7;
|
public static final int EVENT_TYPE_PERMISSION = 7;
|
||||||
|
public static final int EVENT_TYPE_NOOP = 8;
|
||||||
|
|
||||||
public static final int INJECT_SUCCESS = 1;
|
public static final int INJECT_SUCCESS = 1;
|
||||||
public static final int INJECT_FAIL = 0;
|
public static final int INJECT_FAIL = 0;
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* 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.app.IActivityManager;
|
||||||
|
import android.content.pm.IPackageManager;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.pm.PermissionInfo;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.os.ServiceManager;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
import android.view.IWindowManager;
|
||||||
|
|
||||||
|
public class MonkeyPermissionEvent extends MonkeyEvent {
|
||||||
|
private String mPkg;
|
||||||
|
private PermissionInfo mPermissionInfo;
|
||||||
|
|
||||||
|
public MonkeyPermissionEvent(String pkg, PermissionInfo permissionInfo) {
|
||||||
|
super(EVENT_TYPE_PERMISSION);
|
||||||
|
mPkg = pkg;
|
||||||
|
mPermissionInfo = permissionInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int injectEvent(IWindowManager iwm, IActivityManager iam, int verbose) {
|
||||||
|
IPackageManager pm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
|
||||||
|
try {
|
||||||
|
// determine if we should grant or revoke permission
|
||||||
|
int perm = pm.checkPermission(mPermissionInfo.name, mPkg, UserHandle.myUserId());
|
||||||
|
boolean grant = perm == PackageManager.PERMISSION_DENIED;
|
||||||
|
// log before calling pm in case we hit an error
|
||||||
|
System.out.println(String.format(":Permission %s %s to package %s",
|
||||||
|
grant ? "grant" : "revoke", mPermissionInfo.name, mPkg));
|
||||||
|
if (grant) {
|
||||||
|
pm.grantRuntimePermission(mPkg, mPermissionInfo.name, UserHandle.myUserId());
|
||||||
|
} else {
|
||||||
|
pm.revokeRuntimePermission(mPkg, mPermissionInfo.name, UserHandle.myUserId());
|
||||||
|
}
|
||||||
|
return MonkeyEvent.INJECT_SUCCESS;
|
||||||
|
} catch (RemoteException re) {
|
||||||
|
return MonkeyEvent.INJECT_ERROR_REMOTE_EXCEPTION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,178 @@
|
|||||||
|
/*
|
||||||
|
* 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())));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,7 +26,7 @@ import android.view.KeyEvent;
|
|||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -82,8 +82,9 @@ public class MonkeySourceRandom implements MonkeyEventSource {
|
|||||||
public static final int FACTOR_SYSOPS = 7;
|
public static final int FACTOR_SYSOPS = 7;
|
||||||
public static final int FACTOR_APPSWITCH = 8;
|
public static final int FACTOR_APPSWITCH = 8;
|
||||||
public static final int FACTOR_FLIP = 9;
|
public static final int FACTOR_FLIP = 9;
|
||||||
public static final int FACTOR_ANYTHING = 10;
|
public static final int FACTOR_PERMISSION = 10;
|
||||||
public static final int FACTORZ_COUNT = 11; // should be last+1
|
public static final int FACTOR_ANYTHING = 11;
|
||||||
|
public static final int FACTORZ_COUNT = 12; // should be last+1
|
||||||
|
|
||||||
private static final int GESTURE_TAP = 0;
|
private static final int GESTURE_TAP = 0;
|
||||||
private static final int GESTURE_DRAG = 1;
|
private static final int GESTURE_DRAG = 1;
|
||||||
@@ -93,12 +94,13 @@ public class MonkeySourceRandom implements MonkeyEventSource {
|
|||||||
* values after we read any optional values.
|
* values after we read any optional values.
|
||||||
**/
|
**/
|
||||||
private float[] mFactors = new float[FACTORZ_COUNT];
|
private float[] mFactors = new float[FACTORZ_COUNT];
|
||||||
private ArrayList<ComponentName> mMainApps;
|
private List<ComponentName> mMainApps;
|
||||||
private int mEventCount = 0; //total number of events generated so far
|
private int mEventCount = 0; //total number of events generated so far
|
||||||
private MonkeyEventQueue mQ;
|
private MonkeyEventQueue mQ;
|
||||||
private Random mRandom;
|
private Random mRandom;
|
||||||
private int mVerbose = 0;
|
private int mVerbose = 0;
|
||||||
private long mThrottle = 0;
|
private long mThrottle = 0;
|
||||||
|
private MonkeyPermissionUtil mPermissionUtil;
|
||||||
|
|
||||||
private boolean mKeyboardOpen = false;
|
private boolean mKeyboardOpen = false;
|
||||||
|
|
||||||
@@ -117,8 +119,8 @@ public class MonkeySourceRandom implements MonkeyEventSource {
|
|||||||
return KeyEvent.keyCodeFromString(keyName);
|
return KeyEvent.keyCodeFromString(keyName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MonkeySourceRandom(Random random, ArrayList<ComponentName> MainApps,
|
public MonkeySourceRandom(Random random, List<ComponentName> MainApps,
|
||||||
long throttle, boolean randomizeThrottle) {
|
long throttle, boolean randomizeThrottle, boolean permissionTargetSystem) {
|
||||||
// default values for random distributions
|
// default values for random distributions
|
||||||
// note, these are straight percentages, to match user input (cmd line args)
|
// note, these are straight percentages, to match user input (cmd line args)
|
||||||
// but they will be converted to 0..1 values before the main loop runs.
|
// but they will be converted to 0..1 values before the main loop runs.
|
||||||
@@ -132,12 +134,16 @@ public class MonkeySourceRandom implements MonkeyEventSource {
|
|||||||
mFactors[FACTOR_SYSOPS] = 2.0f;
|
mFactors[FACTOR_SYSOPS] = 2.0f;
|
||||||
mFactors[FACTOR_APPSWITCH] = 2.0f;
|
mFactors[FACTOR_APPSWITCH] = 2.0f;
|
||||||
mFactors[FACTOR_FLIP] = 1.0f;
|
mFactors[FACTOR_FLIP] = 1.0f;
|
||||||
|
// disbale permission by default
|
||||||
|
mFactors[FACTOR_PERMISSION] = 0.0f;
|
||||||
mFactors[FACTOR_ANYTHING] = 13.0f;
|
mFactors[FACTOR_ANYTHING] = 13.0f;
|
||||||
mFactors[FACTOR_PINCHZOOM] = 2.0f;
|
mFactors[FACTOR_PINCHZOOM] = 2.0f;
|
||||||
|
|
||||||
mRandom = random;
|
mRandom = random;
|
||||||
mMainApps = MainApps;
|
mMainApps = MainApps;
|
||||||
mQ = new MonkeyEventQueue(random, throttle, randomizeThrottle);
|
mQ = new MonkeyEventQueue(random, throttle, randomizeThrottle);
|
||||||
|
mPermissionUtil = new MonkeyPermissionUtil();
|
||||||
|
mPermissionUtil.setTargetSystemPackages(permissionTargetSystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -410,6 +416,9 @@ public class MonkeySourceRandom implements MonkeyEventSource {
|
|||||||
} else if (cls < mFactors[FACTOR_ROTATION]) {
|
} else if (cls < mFactors[FACTOR_ROTATION]) {
|
||||||
generateRotationEvent(mRandom);
|
generateRotationEvent(mRandom);
|
||||||
return;
|
return;
|
||||||
|
} else if (cls < mFactors[FACTOR_PERMISSION]) {
|
||||||
|
mQ.add(mPermissionUtil.generateRandomPermissionEvent(mRandom));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The remaining event categories are injected as key events
|
// The remaining event categories are injected as key events
|
||||||
@@ -450,8 +459,15 @@ public class MonkeySourceRandom implements MonkeyEventSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean validate() {
|
public boolean validate() {
|
||||||
//check factors
|
boolean ret = true;
|
||||||
return adjustEventFactors();
|
// only populate & dump permissions if enabled
|
||||||
|
if (mFactors[FACTOR_PERMISSION] != 0.0f) {
|
||||||
|
ret &= mPermissionUtil.populatePermissionsMapping();
|
||||||
|
if (ret && mVerbose >= 2) {
|
||||||
|
mPermissionUtil.dump();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret & adjustEventFactors();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setVerbose(int verbose) {
|
public void setVerbose(int verbose) {
|
||||||
|
|||||||
@@ -17,6 +17,9 @@
|
|||||||
package com.android.commands.monkey;
|
package com.android.commands.monkey;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Misc utilities.
|
* Misc utilities.
|
||||||
@@ -26,6 +29,7 @@ public abstract class MonkeyUtils {
|
|||||||
private static final java.util.Date DATE = new java.util.Date();
|
private static final java.util.Date DATE = new java.util.Date();
|
||||||
private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat(
|
private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat(
|
||||||
"yyyy-MM-dd HH:mm:ss.SSS ");
|
"yyyy-MM-dd HH:mm:ss.SSS ");
|
||||||
|
private static PackageFilter sFilter;
|
||||||
|
|
||||||
private MonkeyUtils() {
|
private MonkeyUtils() {
|
||||||
}
|
}
|
||||||
@@ -38,4 +42,72 @@ public abstract class MonkeyUtils {
|
|||||||
return DATE_FORMATTER.format(DATE);
|
return DATE_FORMATTER.format(DATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static PackageFilter getPackageFilter() {
|
||||||
|
if (sFilter == null) {
|
||||||
|
sFilter = new PackageFilter();
|
||||||
|
}
|
||||||
|
return sFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PackageFilter {
|
||||||
|
private Set<String> mValidPackages = new HashSet<>();
|
||||||
|
private Set<String> mInvalidPackages = new HashSet<>();
|
||||||
|
|
||||||
|
private PackageFilter() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addValidPackages(Set<String> validPackages) {
|
||||||
|
mValidPackages.addAll(validPackages);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addInvalidPackages(Set<String> invalidPackages) {
|
||||||
|
mInvalidPackages.addAll(invalidPackages);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasValidPackages() {
|
||||||
|
return mValidPackages.size() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPackageValid(String pkg) {
|
||||||
|
return mValidPackages.contains(pkg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPackageInvalid(String pkg) {
|
||||||
|
return mInvalidPackages.contains(pkg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether we should run against the given package.
|
||||||
|
*
|
||||||
|
* @param pkg The package name.
|
||||||
|
* @return Returns true if we should run against pkg.
|
||||||
|
*/
|
||||||
|
public boolean checkEnteringPackage(String pkg) {
|
||||||
|
if (mInvalidPackages.size() > 0) {
|
||||||
|
if (mInvalidPackages.contains(pkg)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (mValidPackages.size() > 0) {
|
||||||
|
if (!mValidPackages.contains(pkg)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dump() {
|
||||||
|
if (mValidPackages.size() > 0) {
|
||||||
|
Iterator<String> it = mValidPackages.iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
System.out.println(":AllowPackage: " + it.next());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mInvalidPackages.size() > 0) {
|
||||||
|
Iterator<String> it = mInvalidPackages.iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
System.out.println(":DisallowPackage: " + it.next());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user