承接上文,在 【Android Monkey源码解析三】- 运行解析 中,有介绍到run方法中的getSystemInterfaces方法是获取所有系统接口对象的。其中异常捕获和页面控制就是通过ActivityManager的setActivityController方法来实现的,如下:
java
/**
* Attach to the required system interfaces.
*
* @return Returns true if all system interfaces were available.
*/
private boolean getSystemInterfaces() {
mAm = ActivityManager.getService();
if (mAm == null) {
Logger.err.println("** Error: Unable to connect to activity manager; is the system "
+ "running?");
return false;
}
...
try {
mAm.setActivityController(new ActivityController(), true);
mNetworkMonitor.register(mAm);
} catch (RemoteException e) {
Logger.err.println("** Failed talking with activity manager!");
return false;
}
return true;
}
这里,创建了一个新的ActivityController对象,设置给了ActivityManager的setActivityController的第一个参数。下面看下ActivityController的实现,源码地址:https://android.googlesource.com/platform/development/+/refs/heads/android12-release/cmds/monkey/src/com/android/commands/monkey/Monkey.java#265:
java
/**
* Monitor operations happening in the system.
* ActivityController主要实现处理了如下几个事情:
* 1. 页面控制(activityStarting)
* 2. 应用崩溃监控(appCrashed)
* 3. 应用无响应(appNotResponding)
* 4. 系统无响应(appNotResponding)
*/
private class ActivityController extends IActivityController.Stub {
public boolean activityStarting(Intent intent, String pkg) {
// 当Monkey在执行随机事件时,可能进入任何的应用。这里需要对即将进入的应用进行判断
// 如果不是目标测试应用,则不允许跳转。
final boolean allow = isActivityStartingAllowed(intent, pkg);
if (mVerbose > 0) {
// StrictMode's disk checks end up catching this on
// userdebug/eng builds due to PrintStream going to a
// FileOutputStream in the end (perhaps only when
// redirected to a file?) So we allow disk writes
// around this region for the monkey to minimize
// harmless dropbox uploads from monkeys.
StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
Logger.out.println(" // " + (allow ? "Allowing" : "Rejecting") + " start of "
+ intent + " in package " + pkg);
StrictMode.setThreadPolicy(savedPolicy);
}
currentPackage = pkg;
currentIntent = intent;
return allow;
}
// 有三种情况时允许进入目标activity,
// 1. 如果当前要进入的activity是已指定的测试应用包下的;
// 2. 如果设置了允许所有启动activity,此标志位(DEBUG_ALLOW_ANY_STARTS )无设置,条件会不满足;
// 3. 如果启动的activity是启动器的主页面;
private boolean isActivityStartingAllowed(Intent intent, String pkg) {
if (MonkeyUtils.getPackageFilter().checkEnteringPackage(pkg)) {
return true;
}
if (DEBUG_ALLOW_ANY_STARTS != 0) {
return true;
}
// In case the activity is launching home and the default launcher
// package is disabled, allow anyway to prevent ANR (see b/38121026)
final Set<String> categories = intent.getCategories();
if (intent.getAction() == Intent.ACTION_MAIN
&& categories != null
&& categories.contains(Intent.CATEGORY_HOME)) {
try {
final ResolveInfo resolveInfo =
mPm.resolveIntent(intent, intent.getType(), 0,
ActivityManager.getCurrentUser());
final String launcherPackage = resolveInfo.activityInfo.packageName;
if (pkg.equals(launcherPackage)) {
return true;
}
} catch (RemoteException e) {
Logger.err.println("** Failed talking with package manager!");
return false;
}
}
return false;
}
// 当activity进入onResume生命周期时调用
public boolean activityResuming(String pkg) {
StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
Logger.out.println(" // activityResuming(" + pkg + ")");
boolean allow = MonkeyUtils.getPackageFilter().checkEnteringPackage(pkg)
|| (DEBUG_ALLOW_ANY_RESTARTS != 0);
if (!allow) {
if (mVerbose > 0) {
Logger.out.println(" // " + (allow ? "Allowing" : "Rejecting")
+ " resume of package " + pkg);
}
}
currentPackage = pkg;
StrictMode.setThreadPolicy(savedPolicy);
return allow;
}
// 当有应用出现崩溃时调用
public boolean appCrashed(String processName, int pid,
String shortMsg, String longMsg,
long timeMillis, String stackTrace) {
StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
Logger.err.println("// CRASH: " + processName + " (pid " + pid + ")");
Logger.err.println("// Short Msg: " + shortMsg);
Logger.err.println("// Long Msg: " + longMsg);
Logger.err.println("// Build Label: " + Build.FINGERPRINT);
Logger.err.println("// Build Changelist: " + Build.VERSION.INCREMENTAL);
Logger.err.println("// Build Time: " + Build.TIME);
Logger.err.println("// " + stackTrace.replace("\n", "\n// "));
StrictMode.setThreadPolicy(savedPolicy);
// 判断是否有设置mMatchDescription,如果没设置,则直接进入第二层if处理
// 如果有设置mMatchDescription,则通过shortMsg,longMsg,stackTrace进行分别匹配,只要有满足,则进入第二层if处理
if (mMatchDescription == null
|| shortMsg.contains(mMatchDescription)
|| longMsg.contains(mMatchDescription)
|| stackTrace.contains(mMatchDescription)) {
// 如果设置mIgnoreCrashes为false或者设置了mRequestBugreport为true
if (!mIgnoreCrashes || mRequestBugreport) {
synchronized (Monkey.this) {
if (!mIgnoreCrashes) {
mAbort = true;
}
if (mRequestBugreport){
mRequestAppCrashBugreport = true;
mReportProcessName = processName;
}
}
return !mKillProcessAfterError;
}
}
return false;
}
public int appEarlyNotResponding(String processName, int pid, String annotation) {
return 0;
}
// 出现应用无响应时回调处理
public int appNotResponding(String processName, int pid, String processStats) {
StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
Logger.err.println("// NOT RESPONDING: " + processName + " (pid " + pid + ")");
Logger.err.println(processStats);
StrictMode.setThreadPolicy(savedPolicy);
// 同样地,匹配mMatchDescription设置和未设置的条件判断
if (mMatchDescription == null || processStats.contains(mMatchDescription)) {
synchronized (Monkey.this) {
mRequestAnrTraces = true;
mRequestDumpsysMemInfo = true;
mRequestProcRank = true;
if (mRequestBugreport) {
mRequestAnrBugreport = true;
mReportProcessName = processName;
}
}
if (!mIgnoreTimeouts) {
synchronized (Monkey.this) {
mAbort = true;
}
}
}
return (mKillProcessAfterError) ? -1 : 1;
}
// 出现系统无响应时回调处理
public int systemNotResponding(String message) {
StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
Logger.err.println("// WATCHDOG: " + message);
StrictMode.setThreadPolicy(savedPolicy);
synchronized (Monkey.this) {
if (mMatchDescription == null || message.contains(mMatchDescription)) {
if (!mIgnoreCrashes) {
mAbort = true;
}
if (mRequestBugreport) {
mRequestWatchdogBugreport = true;
}
}
mWatchdogWaiting = true;
}
synchronized (Monkey.this) {
while (mWatchdogWaiting) {
try {
Monkey.this.wait();
} catch (InterruptedException e) {
}
}
}
return (mKillProcessAfterError) ? -1 : 1;
}
}
本篇主要介绍了ActivityController的异常捕获/页面控制处理,下面会介绍在出现应用崩溃(appCrashed),应用无响应(appNotResponding),系统无响应时的处理分析(systemNotResponding)。