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
diff --git a/cmds/monkey/src/com/android/commands/monkey/Monkey.java b/cmds/monkey/src/com/android/commands/monkey/Monkey.java
index dfcb4b0..93bfcf0 100644
--- a/cmds/monkey/src/com/android/commands/monkey/Monkey.java
+++ b/cmds/monkey/src/com/android/commands/monkey/Monkey.java
@@ -31,15 +31,12 @@
import android.os.ServiceManager;
import android.os.StrictMode;
import android.os.SystemClock;
-import android.os.SystemProperties;
import android.os.UserHandle;
import android.view.IWindowManager;
import android.view.Surface;
import java.io.BufferedReader;
import java.io.BufferedWriter;
-import java.io.ByteArrayInputStream;
-import java.io.DataInputStream;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
@@ -47,12 +44,12 @@
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Writer;
-import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
+import java.util.Set;
/**
* Application that injects random key events and other actions into the system.
@@ -181,12 +178,6 @@
/** Package whitelist file. */
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 **/
private ArrayList<String> mMainCategories = new ArrayList<String>();
@@ -251,36 +242,20 @@
private MonkeyNetworkMonitor mNetworkMonitor = new MonkeyNetworkMonitor();
+ private boolean mPermissionTargetSystem = false;
+
// information on the current activity.
public static Intent currentIntent;
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.
*/
private class ActivityController extends IActivityController.Stub {
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) {
// StrictMode's disk checks end up catching this on
// userdebug/eng builds due to PrintStream going to a
@@ -301,7 +276,8 @@
public boolean activityResuming(String pkg) {
StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
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 (mVerbose > 0) {
System.out.println(" // " + (allow ? "Allowing" : "Rejecting")
@@ -559,18 +535,7 @@
if (mVerbose > 0) {
System.out.println(":Monkey: seed=" + mSeed + " count=" + mCount);
- 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());
- }
- }
+ MonkeyUtils.getPackageFilter().dump();
if (mMainCategories.size() != 0) {
Iterator<String> it = mMainCategories.iterator();
while (it.hasNext()) {
@@ -626,7 +591,8 @@
if (mVerbose >= 2) { // check seeding performance
System.out.println("// Seeded: " + mSeed);
}
- mEventSource = new MonkeySourceRandom(mRandom, mMainApps, mThrottle, mRandomizeThrottle);
+ mEventSource = new MonkeySourceRandom(mRandom, mMainApps,
+ mThrottle, mRandomizeThrottle, mPermissionTargetSystem);
mEventSource.setVerbose(mVerbose);
// set any of the factors that has been set
for (int i = 0; i < MonkeySourceRandom.FACTORZ_COUNT; i++) {
@@ -756,11 +722,12 @@
try {
String opt;
+ Set<String> validPackages = new HashSet<>();
while ((opt = nextOption()) != null) {
if (opt.equals("-s")) {
mSeed = nextOptionLong("Seed");
} else if (opt.equals("-p")) {
- mValidPackages.add(nextOptionData());
+ validPackages.add(nextOptionData());
} else if (opt.equals("-c")) {
mMainCategories.add(nextOptionData());
} else if (opt.equals("-v")) {
@@ -812,6 +779,9 @@
} else if (opt.equals("--pct-pinchzoom")) {
int i = MonkeySourceRandom.FACTOR_PINCHZOOM;
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")) {
mPkgBlacklistFile = nextOptionData();
} else if (opt.equals("--pkg-whitelist-file")) {
@@ -845,6 +815,8 @@
} else if (opt.equals("--periodic-bugreport")){
mGetPeriodicBugreport = true;
mBugreportFrequency = nextOptionLong("Number of iterations");
+ } else if (opt.equals("--permission-target-system")){
+ mPermissionTargetSystem = true;
} else if (opt.equals("-h")) {
showUsage();
return false;
@@ -854,6 +826,7 @@
return false;
}
}
+ MonkeyUtils.getPackageFilter().addValidPackages(validPackages);
} catch (RuntimeException ex) {
System.err.println("** Error: " + ex.toString());
showUsage();
@@ -889,7 +862,7 @@
* @param list The destination list.
* @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;
try {
reader = new BufferedReader(new FileReader(fileName));
@@ -921,20 +894,24 @@
* @return Returns false if any error occurs.
*/
private boolean loadPackageLists() {
- if (((mPkgWhitelistFile != null) || (mValidPackages.size() > 0))
+ if (((mPkgWhitelistFile != null) || (MonkeyUtils.getPackageFilter().hasValidPackages()))
&& (mPkgBlacklistFile != null)) {
System.err.println("** Error: you can not specify a package blacklist "
+ "together with a whitelist or individual packages (via -p).");
return false;
}
+ Set<String> validPackages = new HashSet<>();
if ((mPkgWhitelistFile != null)
- && (!loadPackageListFromFile(mPkgWhitelistFile, mValidPackages))) {
+ && (!loadPackageListFromFile(mPkgWhitelistFile, validPackages))) {
return false;
}
+ MonkeyUtils.getPackageFilter().addValidPackages(validPackages);
+ Set<String> invalidPackages = new HashSet<>();
if ((mPkgBlacklistFile != null)
- && (!loadPackageListFromFile(mPkgBlacklistFile, mInvalidPackages))) {
+ && (!loadPackageListFromFile(mPkgBlacklistFile, invalidPackages))) {
return false;
}
+ MonkeyUtils.getPackageFilter().addInvalidPackages(invalidPackages);
return true;
}
@@ -1014,7 +991,7 @@
for (int a = 0; a < NA; a++) {
ResolveInfo r = mainApps.get(a);
String packageName = r.activityInfo.applicationInfo.packageName;
- if (checkEnteringPackage(packageName)) {
+ if (MonkeyUtils.getPackageFilter().checkEnteringPackage(packageName)) {
if (mVerbose >= 2) { // very verbose
System.out.println("// + Using main activity " + r.activityInfo.name
+ " (from package " + packageName + ")");
@@ -1352,6 +1329,7 @@
usage.append(" [--pct-nav PERCENT] [--pct-majornav PERCENT]\n");
usage.append(" [--pct-appswitch PERCENT] [--pct-flip 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-whitelist-file PACKAGE_WHITELIST_FILE]\n");
usage.append(" [--wait-dbg] [--dbg-no-events]\n");
@@ -1365,6 +1343,7 @@
usage.append(" [--script-log]\n");
usage.append(" [--bugreport]\n");
usage.append(" [--periodic-bugreport]\n");
+ usage.append(" [--permission-target-system]\n");
usage.append(" COUNT\n");
System.err.println(usage.toString());
}
diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeyEvent.java b/cmds/monkey/src/com/android/commands/monkey/MonkeyEvent.java
index 0a06604..ccae799 100644
--- a/cmds/monkey/src/com/android/commands/monkey/MonkeyEvent.java
+++ b/cmds/monkey/src/com/android/commands/monkey/MonkeyEvent.java
@@ -31,7 +31,8 @@
public static final int EVENT_TYPE_ACTIVITY = 4;
public static final int EVENT_TYPE_FLIP = 5; // Keyboard flip
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_FAIL = 0;
diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeyPermissionEvent.java b/cmds/monkey/src/com/android/commands/monkey/MonkeyPermissionEvent.java
new file mode 100644
index 0000000..130827b
--- /dev/null
+++ b/cmds/monkey/src/com/android/commands/monkey/MonkeyPermissionEvent.java
@@ -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;
+ }
+ }
+}
diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeyPermissionUtil.java b/cmds/monkey/src/com/android/commands/monkey/MonkeyPermissionUtil.java
new file mode 100644
index 0000000..8ab4937
--- /dev/null
+++ b/cmds/monkey/src/com/android/commands/monkey/MonkeyPermissionUtil.java
@@ -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())));
+ }
+}
diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceRandom.java b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceRandom.java
index af6a231..1762f17 100644
--- a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceRandom.java
+++ b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceRandom.java
@@ -26,7 +26,7 @@
import android.view.MotionEvent;
import android.view.Surface;
-import java.util.ArrayList;
+import java.util.List;
import java.util.Random;
/**
@@ -82,8 +82,9 @@
public static final int FACTOR_SYSOPS = 7;
public static final int FACTOR_APPSWITCH = 8;
public static final int FACTOR_FLIP = 9;
- public static final int FACTOR_ANYTHING = 10;
- public static final int FACTORZ_COUNT = 11; // should be last+1
+ public static final int FACTOR_PERMISSION = 10;
+ 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_DRAG = 1;
@@ -93,12 +94,13 @@
* values after we read any optional values.
**/
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 MonkeyEventQueue mQ;
private Random mRandom;
private int mVerbose = 0;
private long mThrottle = 0;
+ private MonkeyPermissionUtil mPermissionUtil;
private boolean mKeyboardOpen = false;
@@ -117,8 +119,8 @@
return KeyEvent.keyCodeFromString(keyName);
}
- public MonkeySourceRandom(Random random, ArrayList<ComponentName> MainApps,
- long throttle, boolean randomizeThrottle) {
+ public MonkeySourceRandom(Random random, List<ComponentName> MainApps,
+ long throttle, boolean randomizeThrottle, boolean permissionTargetSystem) {
// default values for random distributions
// 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.
@@ -132,12 +134,16 @@
mFactors[FACTOR_SYSOPS] = 2.0f;
mFactors[FACTOR_APPSWITCH] = 2.0f;
mFactors[FACTOR_FLIP] = 1.0f;
+ // disbale permission by default
+ mFactors[FACTOR_PERMISSION] = 0.0f;
mFactors[FACTOR_ANYTHING] = 13.0f;
mFactors[FACTOR_PINCHZOOM] = 2.0f;
mRandom = random;
mMainApps = MainApps;
mQ = new MonkeyEventQueue(random, throttle, randomizeThrottle);
+ mPermissionUtil = new MonkeyPermissionUtil();
+ mPermissionUtil.setTargetSystemPackages(permissionTargetSystem);
}
/**
@@ -410,6 +416,9 @@
} else if (cls < mFactors[FACTOR_ROTATION]) {
generateRotationEvent(mRandom);
return;
+ } else if (cls < mFactors[FACTOR_PERMISSION]) {
+ mQ.add(mPermissionUtil.generateRandomPermissionEvent(mRandom));
+ return;
}
// The remaining event categories are injected as key events
@@ -450,8 +459,15 @@
}
public boolean validate() {
- //check factors
- return adjustEventFactors();
+ boolean ret = true;
+ // 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) {
diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeyUtils.java b/cmds/monkey/src/com/android/commands/monkey/MonkeyUtils.java
index aa7a666..8b447c0 100644
--- a/cmds/monkey/src/com/android/commands/monkey/MonkeyUtils.java
+++ b/cmds/monkey/src/com/android/commands/monkey/MonkeyUtils.java
@@ -17,6 +17,9 @@
package com.android.commands.monkey;
import java.text.SimpleDateFormat;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
/**
* Misc utilities.
@@ -26,6 +29,7 @@
private static final java.util.Date DATE = new java.util.Date();
private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss.SSS ");
+ private static PackageFilter sFilter;
private MonkeyUtils() {
}
@@ -38,4 +42,72 @@
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());
+ }
+ }
+ }
+ }
}