Application与Activity是Android中非常重要的组件之其二,当然更多提起的还是Activity,它与用户界面有更直接的关系;当点击设备App图标时,界面上展示给用户能看到过程中,就包含启动Application与Activity的过程。应用运行的一刻,Android系统会为应用创建一个Application对象,这个对象有数据传递、数据共享和数据缓存等功能,它就如同一个容器一样,可以在里面存取信息。而Activity在启动后它就像是一个载体,这个载体如同窗口一样,解析开发定义好的内容(xml定义控件)解析然后展示在这个窗口中,然后用户看到这个载体的内容,在内容有操作后Activity会拿到用户的操作并反馈。
为什么要说到Application?
在一系列Android基础学习上都是基于对Android应用测试更深的碰触,每一次的困惑都需要通过这些基础去解决。在学习UiAutomator基于Instrumentation运行的过程中,就引发出Instrumentation到底是什么东东,从而到了Application对象的创建。下面进入源码分析
一、InStrumentation的OnCreate过程
用户点击应用程序,首先先创建一个应用进程,然后进入到ActivityThread的main方法中,ActivityThread类通常就是我们说的UI线程(主线程),一个进程对应一个ActivityThread,用于调度Activity的生命周期,Service的生命周期,以及调度Instrumentation的创建。
1.执行ActivityThread的main函数,初始化一个ActivityThread实例,然后调用attach方法。顺便提提在说Looper原理中提到的主线程自动创建Looper对象的源码也是这里。
public static void main(String[] args) {
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}AsyncTask.init();
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}Looper.loop();
}
2.在ActivityThread这个类中是有一个Instrumentation成员变量mInstrumentation。执行attach方法,入参是false,在attach的if语句块中变成ture,并没有对mInstrumentation做任何事情,所以mInstrumentation还是一个空对象。然后主要看一下ActivityManagerNative.getDefault()得到一个IactivityManager对象,然后执行了attachApplication方法。但是通过源码可以看到IActivityManager它是一个接口,而实现这个接口的就是ActivityManagerNative类。
final ApplicationThread mAppThread = new ApplicationThread();
private void attach(boolean system) {
if (!system) {
final IActivityManager mgr = ActivityManagerNative.getDefault();
try {
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
// Ignore
}
} else {mInstrumentation = new Instrumentation();
}
}
3.继续看getDefault方法
(1)调用的是gDefault方法
static public IActivityManager getDefault() {
return gDefault.get();
}
(2)通过ServiceManager.getService()获得了一个IBinder引用,这个IBinder引用其实就是ActivityManagerService的引用。
private static final Singleton
gDefault = new Singleton () {
protected IActivityManager create() {
IBinder b = ServiceManager.getService("activity");
if (false) {
Log.v("ActivityManager", "default service binder = " + b);
}
IActivityManager am = asInterface(b);
if (false) {
Log.v("ActivityManager", "default service = " + am);
}
return am;
}
};
(3)因为在在SystemServer中会调用ActivityManagerService的setSystemProcess()方法:在setSystemProcess()中,会调用ServiceManager的addService()方法,把ActivityManagerService的引用存储到ServiceManager中进行管理。所以现在通过ServiceManager.getService()取出的activity实际就是ActivityManagerService(Context.ACTIVITY_SERVICE的值就是activity)。
public void setSystemProcess() {
ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);
ServiceManager.addService("meminfo", new MemBinder(this));
ServiceManager.addService("gfxinfo", new GraphicsBinder(this));
ServiceManager.addService("dbinfo", new DbBinder(this));
}
(4)然后把这个ActivityManagerService这个引用作为入参调用了asInterface方法,最后返回一个ActivityManagerProxy,这个ActivityManagerProxy是实现IActivityManager接口的
static public IActivityManager asInterface(IBinder obj) {
if (obj == null) {
return null;
}
IActivityManager in =
(IActivityManager)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}return new ActivityManagerProxy(obj);
}
4.然后回到ActivityThread的attach方法,调用了attachApplication方法,这个方法在ActivityManagerProxy中也有,但是ActivityManagerService复写了这个方法,所以调用的是ActivityManagerService的attachApplication方法,入参的是ApplicationThread,它是ActivityThread的内部类继承了ApplicationThreadNative类,而ApplicationThreadNative类又是继承了Binder类,所以在这里ApplicationThread充当了Binder的作用,来到ActivityManagerService的attachApplication方法
public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid);
Binder.restoreCallingIdentity(origId);
}
}
5.调用了ActivityManagerService的attachApplicationLocked方法
ActivityStackSupervisor mStackSupervisor;
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {ProcessRecord app;
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid);
}
thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(mConfiguration), app.compat, getCommonServicesLocked(),
mCoreSettingsObserver.getCoreSettingsLocked());if (mStackSupervisor.attachApplicationLocked(app)) {
didSomething = true;
}
}
先看看ProcessRecord 实例app的通过mPidsSelfLocked这个集合拿到的,然后看thread.bindApplication这里,thread是入参的ApplicationThread对象,也就是调用了ApplicationThread的bindApplication方法,但是这里有一个很重要的入参app.instrumentationClass。先放在这里,后面说到Instrumentation还会继续说到这里;在执行完bindApplication()之后,会调用ActivityStackSupervisor的attachApplicationLocked()方法来,在该方法中会调用realStartActivityLocked()方法来启动一个Activity,这个Activity也就是我们默认的首页Activity,也是我们常用的MainActivity。
6.后面再看Activity,先记下往下看,调用的ApplicationThread的bindApplication方法
public final void bindApplication(String processName, ApplicationInfo appInfo,
Listproviders, ComponentName instrumentationName,
ProfilerInfo profilerInfo, Bundle instrumentationArgs,
IInstrumentationWatcher instrumentationWatcher,
IUiAutomationConnection instrumentationUiConnection, int debugMode,
boolean enableOpenGlTrace, boolean isRestrictedBackupMode, boolean persistent,
Configuration config, CompatibilityInfo compatInfo, Mapservices,
Bundle coreSettings) {AppBindData data = new AppBindData();
data.processName = processName;
data.appInfo = appInfo;
data.providers = providers;
data.instrumentationName = instrumentationName;
data.instrumentationArgs = instrumentationArgs;
data.instrumentationWatcher = instrumentationWatcher;
data.instrumentationUiAutomationConnection = instrumentationUiConnection;
data.debugMode = debugMode;
data.enableOpenGlTrace = enableOpenGlTrace;
data.restrictedBackupMode = isRestrictedBackupMode;
data.persistent = persistent;
data.config = config;
data.compatInfo = compatInfo;
data.initProfilerInfo = profilerInfo;
sendMessage(H.BIND_APPLICATION, data);
}
实例化一个AppBindData对象,然后给成员变量赋值,这里继续关注instrumentationName这个变量值,然后作为入参调用sendMessage。它是从ActivityManagerService的attachApplicationLocked方法中调用bindApplication方法入参的app.instrumentationClass就是这里的instrumentationName。H类它是ActivityThread的内部类,继承的是Handler,H.BIND_APPLICATION返回的值就是BIND_APPLICATION,然后调用了sendMessage方法。
7.ApplicationThread的sendMessage方法
private void sendMessage(int what, Object obj) {
sendMessage(what, obj, 0, 0, false);
}private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
if (DEBUG_MESSAGES) Slog.v(
TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
+ ": " + arg1 + " / " + obj);
Message msg = Message.obtain();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.arg2 = arg2;
if (async) {
msg.setAsynchronous(true);
}
mH.sendMessage(msg);
}
而mH是实例化H类的实例,调用了mH的sendMessage方法发送一个Message消息对象(建议看一下Handler机制)
8.根据Handler机制,消息是由handleMessage处理的,所以来到了mH对象的handleMessage方法,在该方法中是一个switch,匹配BIND_APPLICATION是调用了handleBindApplication方法,入参是AppBindData对象。
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case BIND_APPLICATION:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
AppBindData data = (AppBindData)msg.obj;
handleBindApplication(data);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
}
if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));
}
9.来到handleBindApplication方法,看核心代码,判断了data.instrumentationName的值是否为空,来决定在ActivityThread中Instrumentation实例化。
(1)不为空,通过ClassLoader的loadClass方法得到instrumentationName这个变量类名并实例化赋值给mInstrumentation,然后执行init初始化。
(2)为空则直接实例化Instrumentation对象。
private void handleBindApplication(AppBindData data) {
if (data.instrumentationName != null) {
try {
java.lang.ClassLoader cl = instrContext.getClassLoader();
mInstrumentation = (Instrumentation)
cl.loadClass(data.instrumentationName.getClassName()).newInstance();
} catch (Exception e) {
throw new RuntimeException(
"Unable to instantiate instrumentation "
+ data.instrumentationName + ": " + e.toString(), e);
}mInstrumentation.init(this, instrContext, appContext,
new ComponentName(ii.packageName, ii.name), data.instrumentationWatcher,
data.instrumentationUiAutomationConnection);} else {
mInstrumentation = new Instrumentation();
}.......
mInstrumentation.onCreate(data.instrumentationArgs);
......
mInstrumentation.callApplicationOnCreate(app);}
然后往下看,实例化后mInstrumentation对象,调用了onCreate方法;然后再通过mInstrumentation调用了callApplicationOnCreate方法,而callApplicationOnCreate实际就是调用了Application的onCreate方法。所以说Instrumentation比Application先执行onCreate方法,而所谓的Activity,可以结合回到上面第5点更加是在Application之后了。
二、探究app.instrumentationClass的来源
判断data.instrumentationName的值为空来决定ActivityThread类中mInstrumentation对象是什么,所以要看看data.instrumentationName是什么?找到ActivityManagerService的attachApplicationLocked方法中调用bindApplication方法入参的app.instrumentationClass,在第6点中可以看到app是ProcessRecord对象,所以找到ProcessRecord类,根据ProcessRecord类知道instrumentationClass是ComponentName对象,但是在整个ProcessRecord类中并没有找到实例化instrumentationClass的代码。然后就是要看看ProcessRecord 通过mPidsSelfLocked这个集合get的,那么是在什么时候put的呢?put的ProcessRecord 对象有没有给成员变量instrumentationClass赋值呢?
先假设一下,在点击桌面APP图标启动应用时,data.instrumentationName是空的,所以走else语句块,new了一个Instrumentation对象运行。
然后再回顾到《Appium基础学习之 | UiAutomator2.0使用》文章中,UiAutomator基于Instrumentation运行的命令:
adb shell am instrument -w -r -e debug false -e 'ymxh.uiautomation.uiauto2test.ExampleInstrumentedTest' io.appium.uiautomator2.server.test/androidx.test.runner.AndroidJUnitRunner
1.Shell执行am命令,在android源码包\frameworks\base\cmds\am目录下找到am的shell文件,打开后内容很简单,先引入am.jar包,然后运行com.android.commands.am.Am,$@表示全部参数
base=/system
export CLASSPATH=$base/framework/am.jar
exec app_process $base/bin com.android.commands.am.Am "$@"
2.在源码中找到Am.java类,找到主函数,实例化Am对象调用run方法。在Am中找不到入参为args参数的run方法,但是Am是继承了BaseCommand,所以调用的是BaseCommand的run方法。
public class Am extends BaseCommand {
private IActivityManager mAm
public static void main(String[] args) {
(new Am()).run(args);
}}
3.来到BaseCommand的run方法调用的是onRun(),Am重写了onRun()方法,所以又回到Am的onRun方法;在Am的onRun方法中,首先通过BaseCommand的nextArgRequired方法得到下一个子命令instrument,可以看到am很多子命令,如果后续有用到再说,这里重点是instrument,执行了runInstrument方法。
public void onRun() throws Exception {
mAm = ActivityManagerNative.getDefault();
String op = nextArgRequired();
else if (op.equals("instrument")) {
runInstrument();
}}
4.调用了Am的runInstrument方法
private void runInstrument() throws Exception {
String opt;
while ((opt=nextOption()) != null) {
if (opt.equals("-p")) {
profileFile = nextArgRequired();
} else if (opt.equals("-w")) {
wait = true;
} else if (opt.equals("-r")) {
rawMode = true;
} else if (opt.equals("-e")) {
argKey = nextArgRequired();
argValue = nextArgRequired();
args.putString(argKey, argValue);
} else if (opt.equals("--no_window_animation")
|| opt.equals("--no-window-animation")) {
no_window_animation = true;
} else if (opt.equals("--user")) {
userId = parseUserArg(nextArgRequired());
} else if (opt.equals("--abi")) {
abi = nextArgRequired();
} else {
System.err.println("Error: Unknown option: " + opt);
return;
}
}
一个while循环读取参数,如-w给wait赋值true,-r、-e开头后面的参数都拿到后赋值
ComponentName cn = ComponentName.unflattenFromString(cnArg);
然后cn是ComponentName对象,调用unflattenFromString方法返回。调用unflattenFromString方法入参的是cnArg,这个值通过BaseCommand的nextArgRequired方法获取下一个命令行中参数,也就是io.appium.uiautomator2.server.test/androidx.test.runner.AndroidJUnitRunner这个参数。因为在前面的while循环已经把前面的参数都取出来了,最后一个就是io.appium.uiautomator2.server.test/androidx.test.runner.AndroidJUnitRunner。
InstrumentationWatcher watcher = null;
UiAutomationConnection connection = null;
if (wait) {
watcher = new InstrumentationWatcher();
watcher.setRawOutput(rawMode);
connection = new UiAutomationConnection();
}
然后实例化InstrumentationWatcher、UiAutomationConnection两个对象
if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher, connection, userId, abi)) {
throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString());
}
}
再接着往下看mAm.startInstrumentation,mAm是在上面onRun方法通过ActivityManagerNative.getDefault()得到一个IActivityManager对象,这个在上面用到过啊,实际就是ActivityManagerService引用,然后调用了asInterface方法,最后返回一个ActivityManagerProxy。所以执行的是ActivityManagerProxy的startInstrumentation方法。
5.再接着往下看startInstrumentation入参,首先是cn,在上面说过是通过ComponentName类的unflattenFromString方法返回的,所有来到unflattenFromString方法
public final class ComponentName implements Parcelable, Cloneable, Comparable
{
private final String mPackage;
private final String mClass;public ComponentName(String pkg, String cls) {
if (pkg == null) throw new NullPointerException("package name is null");
if (cls == null) throw new NullPointerException("class name is null");
mPackage = pkg;
mClass = cls;
}public static ComponentName unflattenFromString(String str) {
int sep = str.indexOf('/');
if (sep < 0 || (sep+1) >= str.length()) {
return null;
}
String pkg = str.substring(0, sep);
String cls = str.substring(sep+1);
if (cls.length() > 0 && cls.charAt(0) == '.') {
cls = pkg + cls;
}
return new ComponentName(pkg, cls);
}}
先通过indexOf得到入参字符串中反斜线/的下标位置,然后通过substring分别得到反斜线/前面与后面的值。也就是pkg=io.appium.uiautomator2.server.test,cls=androidx.test.runner.AndroidJUnitRunner。然后再实例化ComponentName对象返回,这里把两个值都给了ComponentName对象的成员变量mPackage、mClass。
6.再回到startInstrumentation的入参第二个参数profileFile,命令行没有-p,所以profileFile为null;第三个参数是0,第四个参数是Bundle对象,第五个参数InstrumentationWatcher对象,第六个参数UiAutomationConnection对象,第七个参数调用UserHandle.USER_CURRENT得到的值是-2,第八个参数null
7.知道这些入参值后,来到ActivityManagerProxy的startInstrumentation方法
public boolean startInstrumentation(ComponentName className, String profileFile,
int flags, Bundle arguments, IInstrumentationWatcher watcher,
IUiAutomationConnection connection, int userId, String instructionSet)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
ComponentName.writeToParcel(className, data);
data.writeString(profileFile);
data.writeInt(flags);
data.writeBundle(arguments);
data.writeStrongBinder(watcher != null ? watcher.asBinder() : null);
data.writeStrongBinder(connection != null ? connection.asBinder() : null);
data.writeInt(userId);
data.writeString(instructionSet);
mRemote.transact(START_INSTRUMENTATION_TRANSACTION, data, reply, 0);
reply.readException();
boolean res = reply.readInt() != 0;
reply.recycle();
data.recycle();
return res;
}
通过Parcel对象写入一些数据,然后主要看mRemote.transact(START_INSTRUMENTATION_TRANSACTION, data, reply, 0)这行代码,mRemote是执行ActivityManagerNative.getDefault()的时候通过asInterface方法实例化ActivityManagerProxy对象时入参的ActivityManagerService引用;所以这里是调用了ActivityManagerService的transact方法,在ActivityManagerService类中没有transact方法,来到父类ActivityManagerNative中找,同样没有transact方法;再到Binder类中找到,然后根据代码调用关系最后是到了ActivityManagerService类调用了startInstrumentation方法。
8.来到ActivityManagerService类调用了startInstrumentation方法
public boolean startInstrumentation(ComponentName className,
String profileFile, int flags, Bundle arguments,
IInstrumentationWatcher watcher, IUiAutomationConnection uiAutomationConnection,
int userId, String abiOverride) {
......
ProcessRecord app = addAppLocked(ai, false, abiOverride);
app.instrumentationClass = className;
app.instrumentationInfo = ai;
app.instrumentationProfileFile = profileFile;
app.instrumentationArguments = arguments;
app.instrumentationWatcher = watcher;
app.instrumentationUiAutomationConnection = uiAutomationConnection;
app.instrumentationResultClass = className;
Binder.restoreCallingIdentity(origId);
}
}
终于是在这里找到了ProcessRecord对象,而instrumentationClass的值也是在这里赋值了;一切悬案好像都要揭开的样子了哦。调用了addAppLocked方法返回的ProcessRecord对象,所以往下看。
9.来到ActivityManagerService的addAppLocked方法
final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated,
String abiOverride) {
ProcessRecord app;
if (!isolated) {
app = getProcessRecordLocked(info.processName, info.uid, true);
} else {
app = null;
}if (app == null) {
app = newProcessRecordLocked(info, null, isolated, 0);
mProcessNames.put(info.processName, app.uid, app);
if (isolated) {
mIsolatedProcesses.put(app.uid, app);
}
updateLruProcessLocked(app, false, null);
updateOomAdjLocked();
}......
if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
mPersistentStartingProcesses.add(app);
startProcessLocked(app, "added application", app.processName, abiOverride,
null /* entryPoint */, null /* entryPointArgs */);
}return app;
}
通过一系列方法及判断得到ProcessRecord(这里顺便提提ProcessRecord这个类,整个进程中只有一个ProcessRecord对象,它会记录一系列的进程数据可以贯穿整个生命周期);然后看看startProcessLocked方法启动进程
ProcessRecord类讲解:https://blog.csdn.net/tonyandroid1984/article/details/70224827
10.来到ActivityManagerService的startProcessLocked方法
private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
Process.ProcessStartResult startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
app.info.dataDir, entryPointArgs);
synchronized (mPidsSelfLocked) {
this.mPidsSelfLocked.put(startResult.pid, app);
if (isActivityProcess) {
Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
msg.obj = app;
mHandler.sendMessageDelayed(msg, startResult.usingWrapper
? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
}
}
}
核心代码是执行Process.start是socket通信告知Zygote创建fork子进程,在子进程中会接着关闭socket,调用ZygoteInit.invokeStaticMain(cloader, className, mainArgs),即调用ActivityThread.main(), 新的应用进程会从ActivityThread 的 main()函数处开始执行;具体实现比较复杂就不多说了,可以参考【android进程创建分析】;往下看可以看到mPidsSelfLocked这个集合put的所在之处了,入参pid、ProcessRecord加入集合中。
11.然后回到ActivityManagerService类调用了startInstrumentation方法
public boolean startInstrumentation(ComponentName className,
String profileFile, int flags, Bundle arguments,
IInstrumentationWatcher watcher, IUiAutomationConnection uiAutomationConnection,
int userId, String abiOverride) {
......
ProcessRecord app = addAppLocked(ai, false, abiOverride);
app.instrumentationClass = className;
app.instrumentationInfo = ai;
app.instrumentationProfileFile = profileFile;
app.instrumentationArguments = arguments;
app.instrumentationWatcher = watcher;
app.instrumentationUiAutomationConnection = uiAutomationConnection;
app.instrumentationResultClass = className;
Binder.restoreCallingIdentity(origId);
}
}
返回的ProcessRecord给成员变量赋值,app.instrumentationClass复制的className是Am的runInstrument方法初始化ComponentName得到的。然后进程再开始从ActivityThread 的 main()函数处开始执行,这样就正式回到上面的第一大点InStrumentation的OnCreate过程。
三、KO:
回到上面第一大点,代码太混乱,画个图总结一下
1.InStrumentation的OnCreate过程图
2.通过adb shell am instrument命令行运行源码分析图
从命令行这边运行最后还是会调用ActivityThread的main函数,所以又回到了上面的流程:
(1)在之前留下的问题中ProcessRecord 对象通过mPidsSelfLocked这个集合get得到的,而来到ActivityThread的handleBindApplication的方法中,从入参分析data.instrumentationName的值其实就是app.instrumentationClass;
(2)而app.instrumentationClass是一个ComponentName对象,这个ComponentName对象在adb shell am instrment命令行执行源码分析流程中可以看到,在实例化ComponentName对象这里把两个值pkg=io.appium.uiautomator2.server.test,cls=androidx.test.runner.AndroidJUnitRunner都给了ComponentName对象的成员变量mPackage、mClass。
(3)到ActivityThread的成员变量mInstrumentation实例的初始化,判断data.instrumentationName不为空,则执行代码
mInstrumentation = (Instrumentation)
cl.loadClass(data.instrumentationName.getClassName()).newInstance();
首先data.instrumentationName是指ComponentName对象,然后调用getClassName方法,这个方法得到就是mClass的值,然后反射实例化最终得到的是AndroidJUnitRunner的实例,AndroidJUnitRunner是继承Instrumentation的。
最终结论:用adb shell am instrument命令执行测试,mInstrumentation这个实例指向的并不是默认的Instrumentation而是命令中指定的AndroidJUnitRunner,所以后面调用的是AndroidJUnitRunner的onCreate方法开始执行测试。