Android基础知识学习-Instrumentation启动源码简析

    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<IActivityManager> gDefault = new Singleton<IActivityManager>() {
        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,
                List<ProviderInfo> providers, ComponentName instrumentationName,
                ProfilerInfo profilerInfo, Bundle instrumentationArgs,
                IInstrumentationWatcher instrumentationWatcher,
                IUiAutomationConnection instrumentationUiConnection, int debugMode,
                boolean enableOpenGlTrace, boolean isRestrictedBackupMode, boolean persistent,
                Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services,
                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<ComponentName> {
    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方法开始执行测试。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值