转载请注明出处:http://blog.csdn.net/ahence/article/details/54959235

Instrumentation概念

官方说明

Instrumentation类位于android.app包中,继承自java.lang.Object,一些测试用类如InstrumentationTestRunner或MultiDexTestRunner直接或间接继承自该类。官方对于该类的解释如下:

Base class for implementing application instrumentation code. When running with instrumentation turned on, this class will be instantiated for you before any of the application code, allowing you to monitor all of the interaction the system has with the application. An Instrumentation implementation is described to the system through an AndroidManifest.xml’s instrumentation tag.

大意是当instrumentation开启的话,它会在应用程序的任何组件创建之前初始化,可以用来监控系统与应用的所有交互。系统可以根据AndroidManifest.xml中的 instrumentation 标签来实现instrumentation。

在AndroidManifest.xml中的声明方式及属性解释

语法:

<instrumentation android:functionalTest=["true" | "false"]                 android:handleProfiling=["true" | "false"]                 android:icon="drawable resource"                 android:label="string resource"                 android:name="string"                 android:targetPackage="string" />

父元素:

manifest

描述:

声明一个Instrumentation类,可以用来监控应用与系统之间的交互。Instrumentation类的对象会在应用的所有组件创建之前初始化。

属性介绍:

android:functionalTest

指定Instrumentation类是否作为一个功能性的测试来运行,如果为true,则是;如果为false,则不是,默认值为false。

android:handleProfiling

指定Instrumentation对象是否开启和关闭分析功能。如果设置为true,那么由Instrumentation对象来决定何时启动、停止分析;如果设置为false,则分析功能会在Instrumentation对象整个运行期间启用。如果设置为true,可以使Instrumentation对象针对一组特定的操作来进行分析,默认值为false。

android:icon

Instrumentation类呈现给用户的图标,这个属性必须设置为一个Drawable资源的引用。

android:label

用户可读的Instrumentation类的标签,这个标签可以被设置为原生字符串或者字符串资源的引用。

android:name

Instrumentation子类的名称,它应当是完整的类名(如,“com.example.project.StringInstrumentation”)。然而,还有一种简写方式,如果这个名称的第一个字符是英文句号,那么它将追加到manifest元素指定的包名的后面。

它没有默认值,必须要设置。

android:targetPackage

Instrumentation对象将要运行的应用。这个应用由在它的manifest文件中由manifest元素指定的包名来确定。

Instrumentation源码分析

构造函数

public Instrumentation() {}

Instrumentation生命周期相关的方法

首先是onCreate方法:

/** * Called when the instrumentation is starting, before any application code * has been loaded.  Usually this will be implemented to simply call * {@link #start} to begin the instrumentation thread, which will then * continue execution in {@link #onStart}. *  * 

If you do not need your own thread -- that is you are writing your * instrumentation to be completely asynchronous (returning to the event * loop so that the application can run), you can simply begin your * instrumentation here, for example call {@link Context#startActivity} to * begin the appropriate first activity of the application. * * @param arguments Any additional arguments that were supplied when the * instrumentation was started. */public void onCreate(Bundle arguments) {}

当启动一个instrumentation时会调用上述onCreate方法,它会在所有应用程序代码加载完成之前启动。在Instrumentation源码中,它是一个空方法,因此会在其实现类中重写,如在InstrumentationTestRunner中就重写了onCreate,并在最后调用了start()方法。

start方法会启动一个新的线程用来执行instrumentation,代码如下:

/** * Create and start a new thread in which to run instrumentation.  This new * thread will call to {@link #onStart} where you can implement the * instrumentation. */public void start() {    if (mRunner != null) {        throw new RuntimeException("Instrumentation already started");    }    mRunner = new InstrumentationThread("Instr: " + getClass().getName());    mRunner.start();}

其中mRunner是InstrumentationThread的一个实例,表示Instrumentation所在的线程,该线程启动后会执行onStart()方法:

private final class InstrumentationThread extends Thread {    public InstrumentationThread(String name) {        super(name);    }    public void run() {        try {            Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);        } catch (RuntimeException e) {            Log.w(TAG, "Exception setting priority of instrumentation thread "                    + Process.myTid(), e);        }        if (mAutomaticPerformanceSnapshots) {            startPerformanceSnapshot();        }        onStart();    }}

接下来看onStart方法:

/** * Method where the instrumentation thread enters execution.  This allows * you to run your instrumentation code in a separate thread than the * application, so that it can perform blocking operation such as * {@link #sendKeySync} or {@link #startActivitySync}. *  * 

You will typically want to call finish() when this function is done, * to end your instrumentation. */public void onStart() {}

在onStart()里面可以具体实现instrumentation的逻辑,但在Instrumentation中它也是个空方法,需要重写该方法,从而可以测试一些阻塞性的操作,当功能完成时可以调用finish()方法来结束instrumentation,如下:

/** * Terminate instrumentation of the application.  This will cause the * application process to exit, removing this instrumentation from the next * time the application is started.  *   * @param resultCode Overall success/failure of instrumentation.  * @param results Any results to send back to the code that started the  *                instrumentation. */public void finish(int resultCode, Bundle results) {    if (mAutomaticPerformanceSnapshots) {        endPerformanceSnapshot();    }    if (mPerfMetrics != null) {        if (results == null) {            results = new Bundle();        }        results.putAll(mPerfMetrics);    }    if ((mUiAutomation != null) && !mUiAutomation.isDestroyed()) {        mUiAutomation.disconnect();        mUiAutomation = null;    }    mThread.finishInstrumentation(resultCode, results);}

finish方法会终止应用程序的instrumentation,同时应用进程退出,下次该应用再次启动时会移除该instrumentation。

最后是onDestroy方法:

/** * Called when the instrumented application is stopping, after all of the * normal application cleanup has occurred. */public void onDestroy() {}

此方法当应用程序停止检测,且所有应用被清理之后才会执行。

获取Context的两个方法

第一个是获取instrumentation所在包的上下文对象:

/** * Return the Context of this instrumentation's package.  Note that this is * often different than the Context of the application being * instrumentated, since the instrumentation code often lives is a * different package than that of the application it is running against. * See {@link #getTargetContext} to retrieve a Context for the target * application. *  * @return The instrumentation's package context. *  * @see #getTargetContext */public Context getContext() {    return mInstrContext;}

第二个是获取被检测的应用的上下文对象:

/** * Return a Context for the target application being instrumented.  Note * that this is often different than the Context of the instrumentation * code, since the instrumentation code often lives is a different package * than that of the application it is running against. See * {@link #getContext} to retrieve a Context for the instrumentation code. *  * @return A Context in the target application. *  * @see #getContext */public Context getTargetContext() {    return mAppContext;}

为什么会有上面两个不同的Context呢?是因为instrumentation的代码经常运行在另一个包(或者叫进程)中,而被检测的应用是另一个进程。

控制性能分析的几个方法

/** * Check whether this instrumentation was started with profiling enabled. *  * @return Returns true if profiling was enabled when starting, else false. */public boolean isProfiling() {    return mThread.isProfiling();}/** * This method will start profiling if isProfiling() returns true. You should * only call this method if you set the handleProfiling attribute in the  * manifest file for this Instrumentation to true.   */public void startProfiling() {    if (mThread.isProfiling()) {        File file = new File(mThread.getProfileFilePath());        file.getParentFile().mkdirs();        Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);    }}/** * Stops profiling if isProfiling() returns true. */public void stopProfiling() {    if (mThread.isProfiling()) {        Debug.stopMethodTracing();    }}
public void setAutomaticPerformanceSnapshots() {    mAutomaticPerformanceSnapshots = true;    mPerformanceCollector = new PerformanceCollector();}public void startPerformanceSnapshot() {    if (!isProfiling()) {        mPerformanceCollector.beginSnapshot(null);    }}public void endPerformanceSnapshot() {    if (!isProfiling()) {        mPerfMetrics = mPerformanceCollector.endSnapshot();    }}

上面几个方法比较简单,通过注释即可理解其用途。

两个比较重要的内部类

Instrumentation.ActivityResult

该类大家应该很熟悉,我们经常使用startActivityForResult,这个类就是用来封装从第二个Activity返回的结果的,其源码如下:

/** * Description of a Activity execution result to return to the original * activity. */public static final class ActivityResult {    /**     * Create a new activity result.  See {@link Activity#setResult} for      * more information.      *       * @param resultCode The result code to propagate back to the     * originating activity, often RESULT_CANCELED or RESULT_OK     * @param resultData The data to propagate back to the originating     * activity.     */    public ActivityResult(int resultCode, Intent resultData) {        mResultCode = resultCode;        mResultData = resultData;    }    /**     * Retrieve the result code contained in this result.     */    public int getResultCode() {        return mResultCode;    }    /**     * Retrieve the data contained in this result.     */    public Intent getResultData() {        return mResultData;    }    private final int mResultCode;    private final Intent mResultData;}

该类非常简单,维护了一个整型的resultCode以及一个Intent类型的resultData,可以结合常用的onActivityResult回调来印证一下。

Instrumentation.ActivityMonitor

该类官方注释如下:

/** * Information about a particular kind of Intent that is being monitored. * An instance of this class is added to the  * current instrumentation through {@link #addMonitor}; after being added,  * when a new activity is being started the monitor will be checked and, if  * matching, its hit count updated and (optionally) the call stopped and a  * canned result returned. *  * 

An ActivityMonitor can also be used to look for the creation of an * activity, through the {@link #waitForActivity} method. This will return * after a matching activity has been created with that activity object. */public static class ActivityMonitor { ……}

从注释可知ActivityMonitor可以用来监控某个特定Intent的信息,可以通过Instrumentation.addMonitor方法来添加ActivityMonitor的实例。当一个新的Activity被启动时,会匹配Instrumentation中的ActivityMonitory实例列表,如果匹配,就会累加命中计数器。ActivityMonitor也可以被用于获取新创建的Activity,通过waitForActivity方法,可以返回一个匹配IntentFilter的Activity对象。

成员变量
private final IntentFilter mWhich;private final String mClass;private final ActivityResult mResult;private final boolean mBlock;// This is protected by 'Instrumentation.this.mSync'./*package*/ int mHits = 0;// This is protected by 'this'./*package*/ Activity mLastActivity = null;
构造函数

ActivityMonitor有两种构造方法,其一:

/** * Create a new ActivityMonitor that looks for a particular kind of  * intent to be started. *   * @param which The set of intents this monitor is responsible for. * @param result A canned result to return if the monitor is hit; can  *               be null. * @param block Controls whether the monitor should block the activity  *              start (returning its canned result) or let the call *              proceed. *   * @see Instrumentation#addMonitor  */public ActivityMonitor(    IntentFilter which, ActivityResult result, boolean block) {    mWhich = which;    mClass = null;    mResult = result;    mBlock = block;}

其二:

/** * Create a new ActivityMonitor that looks for a specific activity  * class to be started.  *   * @param cls The activity class this monitor is responsible for. * @param result A canned result to return if the monitor is hit; can  *               be null. * @param block Controls whether the monitor should block the activity  *              start (returning its canned result) or let the call *              proceed. *   * @see Instrumentation#addMonitor  */public ActivityMonitor(    String cls, ActivityResult result, boolean block) {    mWhich = null;    mClass = cls;    mResult = result;    mBlock = block;}

比较上面两个构造方法可知,只有一个参数不同:一个需要IntentFilter,而另一个需要Activity的类名。

waitForActivity方法
/** * Block until an Activity is created that matches this monitor,  * returning the resulting activity.  *  * @return Activity */public final Activity waitForActivity() {    synchronized (this) {        while (mLastActivity == null) {            try {                wait();            } catch (InterruptedException e) {            }        }        Activity res = mLastActivity;        mLastActivity = null;        return res;    }}

从注释可知,该方法会阻塞直到有匹配该ActivityMonitor的Activity创建完成,最后将该Activity返回。

waitForActivityWithTimeout方法
/** * Block until an Activity is created that matches this monitor,  * returning the resulting activity or till the timeOut period expires. * If the timeOut expires before the activity is started, return null.  *  * @param timeOut Time to wait in milliseconds before the activity is created. *  * @return Activity */public final Activity waitForActivityWithTimeout(long timeOut) {    synchronized (this) {        if (mLastActivity == null) {            try {                wait(timeOut);            } catch (InterruptedException e) {            }        }        if (mLastActivity == null) {            return null;        } else {            Activity res = mLastActivity;            mLastActivity = null;            return res;        }    }}

上述方法则会有超时限制,超市之后将返回null。

match方法
final boolean match(Context who,                    Activity activity,                    Intent intent) {    synchronized (this) {        if (mWhich != null            && mWhich.match(who.getContentResolver(), intent,                            true, "Instrumentation") < 0) {            return false;        }        if (mClass != null) {            String cls = null;            if (activity != null) {                cls = activity.getClass().getName();            } else if (intent.getComponent() != null) {                cls = intent.getComponent().getClassName();            }            if (cls == null || !mClass.equals(cls)) {                return false;            }        }        if (activity != null) {            mLastActivity = activity;            notifyAll();        }        return true;    }}

上述方法顾名思义,它会在启动Activity时调用。从代码中可知,它先回根据IntentFilter判断是否匹配,然后再根据Activity的类名进行判断。

一系列操作事件方法

  • public boolean invokeMenuActionSync(Activity targetActivity, int id, int flag)
  • public boolean invokeContextMenuAction(Activity targetActivity, int id, int flag)
  • public void sendStringSync(String text)
  • public void sendKeySync(KeyEvent event)
  • public void sendKeyDownUpSync(int key)
  • public void sendCharacterSync(int keyCode)
  • public void sendPointerSync(MotionEvent event)
  • public void sendTrackballEventSync(MotionEvent event)

上述方法主要用于辅助测试,根据方法名及注释即可理解,不做赘述。

ActivityMonitor相关的方法

以下3个方法时用来将ActivityMonitor对象添加到一个ActivityMonitor列表中,具体实现为ArrayList。

public void addMonitor(ActivityMonitor monitor) {    synchronized (mSync) {        if (mActivityMonitors == null) {            mActivityMonitors = new ArrayList();        }        mActivityMonitors.add(monitor);    }}
public ActivityMonitor addMonitor(    IntentFilter filter, ActivityResult result, boolean block) {    ActivityMonitor am = new ActivityMonitor(filter, result, block);    addMonitor(am);    return am;}
public ActivityMonitor addMonitor(    String cls, ActivityResult result, boolean block) {    ActivityMonitor am = new ActivityMonitor(cls, result, block);    addMonitor(am);    return am;}

下面方法用来检查ActivityMonitor是否匹配:

public boolean checkMonitorHit(ActivityMonitor monitor, int minHits) {    waitForIdleSync();    synchronized (mSync) {        if (monitor.getHits() < minHits) {            return false;        }        mActivityMonitors.remove(monitor);    }    return true;}

下面来个方法用来返回匹配的Activity:

public Activity waitForMonitor(ActivityMonitor monitor) {    Activity activity = monitor.waitForActivity();    synchronized (mSync) {        mActivityMonitors.remove(monitor);    }    return activity;}
public Activity waitForMonitorWithTimeout(ActivityMonitor monitor, long timeOut) {    Activity activity = monitor.waitForActivityWithTimeout(timeOut);    synchronized (mSync) {        mActivityMonitors.remove(monitor);    }    return activity;}

最后是删除ActivityMonitor的方法:

/** * Remove an {@link ActivityMonitor} that was previously added with  * {@link #addMonitor}. *   * @param monitor The monitor to remove. *   * @see #addMonitor  */public void removeMonitor(ActivityMonitor monitor) {    synchronized (mSync) {        mActivityMonitors.remove(monitor);    }}

Activity启动流程(Application的创建)

如果你在阅读Instrumentation的源码时发现了关于创建Application和Activity的方法,请不要惊讶,是否瞬间感觉这个类相当重要。我们都知道,每个App都只有一个Application实例,如果在源码中跟踪过Activity的启动过程,也许还记得Application的最终创建就是位于Instrumentation中的。

我们大概浏览一下源码中启动一个Activity的流程,以Activity A启动Activity B为例:

1.startActivity方法有多种重载形式,但最终都会走到startActivityForResult,源码位于Activity.java中,如下:

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,        @Nullable Bundle options) {    if (mParent == null) {        Instrumentation.ActivityResult ar =            mInstrumentation.execStartActivity(                this, mMainThread.getApplicationThread(), mToken, this,                intent, requestCode, options);        if (ar != null) {            mMainThread.sendActivityResult(                mToken, mEmbeddedID, requestCode, ar.getResultCode(),                ar.getResultData());        }        if (requestCode >= 0) {            // If this start is requesting a result, we can avoid making            // the activity visible until the result is received.  Setting            // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the            // activity hidden during this time, to avoid flickering.            // This can only be done when a result is requested because            // that guarantees we will get information back when the            // activity is finished, no matter what happens to it.            mStartedActivity = true;        }        cancelInputsAndStartExitTransition(options);        // TODO Consider clearing/flushing other event sources and events for child windows.    } else {        if (options != null) {            mParent.startActivityFromChild(this, intent, requestCode, options);        } else {            // Note we want to go through this method for compatibility with            // existing applications that may have overridden it.            mParent.startActivityFromChild(this, intent, requestCode);        }    }}

注意到此段代码中已经有了Instrumentation,对应代码如下:

Instrumentation.ActivityResult ar =    mInstrumentation.execStartActivity(        this, mMainThread.getApplicationThread(), mToken, this,        intent, requestCode, options);

我们先来看Activity.java中的mInstrumentation是何时初始化的,然后再看上述方法的具体实现。

经搜索发现mInstrumentation是在Activity的attach方法中赋值的,具体代码为:

mInstrumentation = instr;

那么Activity的attach方法时何时调用的呢?这里先放一放,稍后会提到。

2.接着来看mInstrumentation.execStartActivity( this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options);的具体实现,代码位于Instrumentation.java中:

public ActivityResult execStartActivity(        Context who, IBinder contextThread, IBinder token, Activity target,        Intent intent, int requestCode, Bundle options) {    IApplicationThread whoThread = (IApplicationThread) contextThread;    Uri referrer = target != null ? target.onProvideReferrer() : null;    if (referrer != null) {        intent.putExtra(Intent.EXTRA_REFERRER, referrer);    }    if (mActivityMonitors != null) {        synchronized (mSync) {            final int N = mActivityMonitors.size();            for (int i=0; ifinal ActivityMonitor am = mActivityMonitors.get(i);                if (am.match(who, null, intent)) {                    am.mHits++;                    if (am.isBlocking()) {                        return requestCode >= 0 ? am.getResult() : null;                    }                    break;                }            }        }    }    try {        intent.migrateExtraStreamToClipData();        intent.prepareToLeaveProcess(who);        int result = ActivityManagerNative.getDefault()            .startActivity(whoThread, who.getBasePackageName(), intent,                    intent.resolveTypeIfNeeded(who.getContentResolver()),                    token, target != null ? target.mEmbeddedID : null,                    requestCode, 0, null, options);        checkStartActivityResult(result, intent);    } catch (RemoteException e) {        throw new RuntimeException("Failure from system", e);    }    return null;}

从上述代码不难看出Activity的真正启动逻辑是由下面几句完成的:

int result = ActivityManagerNative.getDefault()    .startActivity(whoThread, who.getBasePackageName(), intent,            intent.resolveTypeIfNeeded(who.getContentResolver()),            token, target != null ? target.mEmbeddedID : null,            requestCode, 0, null, options);checkStartActivityResult(result, intent);

其中最后一句checkStartActivityResult(result, intent);是用来检查Activity的启动情况,我们经常忘记在AndroidManifest.xml注册Activity,从而会报异常:

have you declared this activity in your AndroidManifest.xml?

这句异常就是在checkStartActivityResult(result, intent);中实现的。

言归正传,上述代码中是由ActivityManagerNative.getDefault()来启动Activity的,ActivityManagerNative.getDefault()返回一个IActivityManager对象:

/** * Retrieve the system's default/global activity manager. */static public IActivityManager getDefault() {    return gDefault.get();}

我们知道ActivityManagerNative继承自Binder并实现了IActivityManager接口:

public abstract class ActivityManagerNative extends Binder implements IActivityManager{}

在IActivityManager接口中定义了上述启动Activity的方法,但没有实现:

public int startActivities(IApplicationThread caller, String callingPackage,        Intent[] intents, String[] resolvedTypes, IBinder resultTo,        Bundle options, int userId) throws RemoteException;

其具体实现是在ActivityManagerService中,ActivityManagerService源码路径为:

/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

可以看到ActivityManagerService继承自ActivityManagerNative:

public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {}

3.现在逻辑已经到了ActivityManagerService中,找到对应的启动Activity的源码:

@Overridepublic final int startActivities(IApplicationThread caller, String callingPackage,                                 Intent[] intents, String[] resolvedTypes, IBinder resultTo, Bundle options,                                 int userId) {    enforceNotIsolatedCaller("startActivities");    userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,            false, ALLOW_FULL_ONLY, "startActivity", null);    // TODO: Switch to user app stacks here.    int ret = mStackSupervisor.startActivities(caller, -1, callingPackage, intents,            resolvedTypes, resultTo, options, userId);    return ret;}

分析上述代码发现启动逻辑又转移到了ActivityStackSupervisor中。ActivityStackSupervisor源码路径为:

/frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

由于代码片段比较长,下面仅罗列主要流程:

ActivityStackSupervisor—>startActivities()

ActivityStackSupervisor—>startActivityLocked()

ActivityStackSupervisor—>startActivityUncheckedLocked()

ActivityStack—>startActivityLocked()

ActivityStackSupervisor—>resumeTopActivitiesLocked()

ActivityStack—>resumeTopActivityLocked()

ActivityStack—>resumeTopActivityInnerLocked()

ActivityStackSupervisor—>startSpecificActivityLocked()

ActivityStackSupervisor—>realStartActivityLocked()

其中ActivityStack源码路径为:

/frameworks/base/services/core/java/com/android/server/am/ActivityStack.java

4.在ActivityStackSupervisor的realStartActivityLocked()方法中,有这样一段关键代码:

app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken, System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration), r.compat, r.launchedFromPackage, r.task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results, newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);

其中app.thread类型为IApplicationThread,IApplicationThread的声明如下:

/** * System private API for communicating with the application.  This is given to * the activity manager by an application  when it starts up, for the activity * manager to tell the application about things it needs to do. * * {@hide} */public interface IApplicationThread extends IInterface {}

IApplicationThread接口定义了上述启动Activity的方法,但接口中没有实现:

void scheduleLaunchActivity(Intent intent, IBinder token, int ident,        ActivityInfo info, Configuration curConfig, Configuration overrideConfig,        CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,        int procState, Bundle state, PersistableBundle persistentState,        List pendingResults, List pendingNewIntents,        boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) throws RemoteException;

接下来需要找到IApplicationThread接口的实现者,我们想到ActivityThread中有一个叫做ApplicationThread的内部类:

private class ApplicationThread extends ApplicationThreadNative {}

ApplicationThread继承自ApplicationThreadNative,而ApplicationThreadNative继承自Binder并实现了IApplicationThread接口,所以ApplicationThread就是IApplicationThread的具体实现者。

5.于是Activity的启动流程又变为:

ActivityThread.ApplicationThread—>scheduleLaunchActivity(),源码如下:

@Overridepublic final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,        ActivityInfo info, Configuration curConfig, Configuration overrideConfig,        CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,        int procState, Bundle state, PersistableBundle persistentState,        List pendingResults, List pendingNewIntents,        boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {    updateProcessState(procState, false);    ActivityClientRecord r = new ActivityClientRecord();    r.token = token;    r.ident = ident;    r.intent = intent;    r.referrer = referrer;    r.voiceInteractor = voiceInteractor;    r.activityInfo = info;    r.compatInfo = compatInfo;    r.state = state;    r.persistentState = persistentState;    r.pendingResults = pendingResults;    r.pendingIntents = pendingNewIntents;    r.startsNotResumed = notResumed;    r.isForward = isForward;    r.profilerInfo = profilerInfo;    r.overrideConfig = overrideConfig;    updatePendingConfiguration(curConfig);    sendMessage(H.LAUNCH_ACTIVITY, r);}

源码很简单,就是发送了一个LAUNCH_ACTIVITY的消息给名为H的handler处理,接下来看消息处理逻辑:

case LAUNCH_ACTIVITY: {    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;    r.packageInfo = getPackageInfoNoCheck(            r.activityInfo.applicationInfo, r.compatInfo);    handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);} break;

6.启动逻辑变为

ActivityThread—>handleLaunchActivity()

接着看handleLaunchActivity(r, null, “LAUNCH_ACTIVITY”)的具体实现:

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {    // If we are getting ready to gc after going to the background, well    // we are back active so skip it.    unscheduleGcIdler();    mSomeActivitiesChanged = true;    if (r.profilerInfo != null) {        mProfiler.setProfiler(r.profilerInfo);        mProfiler.startProfiling();    }    // Make sure we are running with the most recent config.    handleConfigurationChanged(null, null);    if (localLOGV) Slog.v(        TAG, "Handling launch of " + r);    // Initialize before creating the activity    WindowManagerGlobal.initialize();    Activity a = performLaunchActivity(r, customIntent);    if (a != null) {        r.createdConfig = new Configuration(mConfiguration);        reportSizeConfigurations(r);        Bundle oldState = r.state;        handleResumeActivity(r.token, false, r.isForward,                !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);        if (!r.activity.mFinished && r.startsNotResumed) {            // The activity manager actually wants this one to start out paused, because it            // needs to be visible but isn't in the foreground. We accomplish this by going            // through the normal startup (because activities expect to go through onResume()            // the first time they run, before their window is displayed), and then pausing it.            // However, in this case we do -not- need to do the full pause cycle (of freezing            // and such) because the activity manager assumes it can just retain the current            // state it has.            performPauseActivityIfNeeded(r, reason);            // We need to keep around the original state, in case we need to be created again.            // But we only do this for pre-Honeycomb apps, which always save their state when            // pausing, so we can not have them save their state when restarting from a paused            // state. For HC and later, we want to (and can) let the state be saved as the            // normal part of stopping the activity.            if (r.isPreHoneycomb()) {                r.state = oldState;            }        }    } else {        // If there was an error, for any reason, tell the activity manager to stop us.        try {            ActivityManagerNative.getDefault()                .finishActivity(r.token, Activity.RESULT_CANCELED, null,                        Activity.DONT_FINISH_TASK_WITH_ACTIVITY);        } catch (RemoteException ex) {            throw ex.rethrowFromSystemServer();        }    }}

其中一行关键代码是:

Activity a = performLaunchActivity(r, customIntent);

接着看ActivityThread—>performLaunchActivity()的实现:

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {    // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");  // 从ActivityClientRecord中得到待启动的Activity组件的信息    ActivityInfo aInfo = r.activityInfo;    if (r.packageInfo == null) {        r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,                Context.CONTEXT_INCLUDE_CODE);    }    ComponentName component = r.intent.getComponent();    if (component == null) {        component = r.intent.resolveActivity(            mInitialApplication.getPackageManager());        r.intent.setComponent(component);    }    if (r.activityInfo.targetActivity != null) {        component = new ComponentName(r.activityInfo.packageName,                r.activityInfo.targetActivity);    }// 通过Instrumentation的newActivity方法来创建Activity对象    Activity activity = null;    try {        java.lang.ClassLoader cl = r.packageInfo.getClassLoader();        activity = mInstrumentation.newActivity(                cl, component.getClassName(), r.intent);        StrictMode.incrementExpectedActivityCount(activity.getClass());        r.intent.setExtrasClassLoader(cl);        r.intent.prepareToEnterProcess();        if (r.state != null) {            r.state.setClassLoader(cl);        }    } catch (Exception e) {        if (!mInstrumentation.onException(activity, e)) {            throw new RuntimeException(                "Unable to instantiate activity " + component                + ": " + e.toString(), e);        }    }    try {      // 创建Application        Application app = r.packageInfo.makeApplication(false, mInstrumentation);        if (localLOGV) Slog.v(TAG, "Performing launch of " + r);        if (localLOGV) Slog.v(                TAG, r + ": app=" + app                + ", appName=" + app.getPackageName()                + ", pkg=" + r.packageInfo.getPackageName()                + ", comp=" + r.intent.getComponent().toShortString()                + ", dir=" + r.packageInfo.getAppDir());        if (activity != null) {            Context appContext = createBaseContextForActivity(r, activity);            CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());            Configuration config = new Configuration(mCompatConfiguration);            if (r.overrideConfig != null) {                config.updateFrom(r.overrideConfig);            }            if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "                    + r.activityInfo.name + " with config " + config);            Window window = null;            if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {                window = r.mPendingRemoveWindow;                r.mPendingRemoveWindow = null;                r.mPendingRemoveWindowManager = null;            }          // 调用Activity的attach方法            activity.attach(appContext, this, getInstrumentation(), r.token,                    r.ident, app, r.intent, r.activityInfo, title, r.parent,                    r.embeddedID, r.lastNonConfigurationInstances, config,                    r.referrer, r.voiceInteractor, window);            if (customIntent != null) {                activity.mIntent = customIntent;            }            r.lastNonConfigurationInstances = null;            activity.mStartedActivity = false;            int theme = r.activityInfo.getThemeResource();            if (theme != 0) {                activity.setTheme(theme);            }            activity.mCalled = false;            if (r.isPersistable()) {                mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);            } else {                mInstrumentation.callActivityOnCreate(activity, r.state);            }            if (!activity.mCalled) {                throw new SuperNotCalledException(                    "Activity " + r.intent.getComponent().toShortString() +                    " did not call through to super.onCreate()");            }            r.activity = activity;            r.stopped = true;            if (!r.activity.mFinished) {                activity.performStart();                r.stopped = false;            }            if (!r.activity.mFinished) {                if (r.isPersistable()) {                    if (r.state != null || r.persistentState != null) {                        mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,                                r.persistentState);                    }                } else if (r.state != null) {                    mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);                }            }            if (!r.activity.mFinished) {                activity.mCalled = false;                if (r.isPersistable()) {                    mInstrumentation.callActivityOnPostCreate(activity, r.state,                            r.persistentState);                } else {                    mInstrumentation.callActivityOnPostCreate(activity, r.state);                }                if (!activity.mCalled) {                    throw new SuperNotCalledException(                        "Activity " + r.intent.getComponent().toShortString() +                        " did not call through to super.onPostCreate()");                }            }        }        r.paused = true;        mActivities.put(r.token, r);    } catch (SuperNotCalledException e) {        throw e;    } catch (Exception e) {        if (!mInstrumentation.onException(activity, e)) {            throw new RuntimeException(                "Unable to start activity " + component                + ": " + e.toString(), e);        }    }    return activity;}

上述代码主要做了4件事情:

  1. 从ActivityClientRecord中得到待启动的Activity组件的信息
  2. 通过Instrumentation的newActivity方法来创建Activity对象
  3. 创建Application对象
  4. 调用新启动Activity的attach方法

上述四个逻辑对应的源码详见中文注释。

对于上述4件事情,我们主要关注以下几点:

1.Instrumentation的newActivity的实现:

/** * Perform instantiation of the process's {@link Activity} object.  The * default implementation provides the normal system behavior. *  * @param cl The ClassLoader with which to instantiate the object. * @param className The name of the class implementing the Activity *                  object. * @param intent The Intent object that specified the activity class being *               instantiated. *  * @return The newly instantiated Activity object. */public Activity newActivity(ClassLoader cl, String className,        Intent intent)        throws InstantiationException, IllegalAccessException,        ClassNotFoundException {    return (Activity)cl.loadClass(className).newInstance();}

很简单,使用类加载器初始化一个Activity对象。

2.再来看下Application对象是如何创建出来的,以下为对应代码:

Application app = r.packageInfo.makeApplication(false, mInstrumentation);

其中r.packageInfo为LoadedApk对象,在LoadedApk类中的具体实现如下:

public Application makeApplication(boolean forceDefaultAppClass,        Instrumentation instrumentation) {    if (mApplication != null) {        return mApplication;    }    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");    Application app = null;    String appClass = mApplicationInfo.className;    if (forceDefaultAppClass || (appClass == null)) {        appClass = "android.app.Application";    }    try {        java.lang.ClassLoader cl = getClassLoader();        if (!mPackageName.equals("android")) {            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,                    "initializeJavaContextClassLoader");            initializeJavaContextClassLoader();            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);        }        ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);        app = mActivityThread.mInstrumentation.newApplication(                cl, appClass, appContext);        appContext.setOuterContext(app);    } catch (Exception e) {        if (!mActivityThread.mInstrumentation.onException(app, e)) {            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);            throw new RuntimeException(                "Unable to instantiate application " + appClass                + ": " + e.toString(), e);        }    }    mActivityThread.mAllApplications.add(app);    mApplication = app;    if (instrumentation != null) {        try {            instrumentation.callApplicationOnCreate(app);        } catch (Exception e) {            if (!instrumentation.onException(app, e)) {                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);                throw new RuntimeException(                    "Unable to create application " + app.getClass().getName()                    + ": " + e.toString(), e);            }        }    }    // Rewrite the R 'constants' for all library apks.    SparseArray packageIdentifiers = getAssets(mActivityThread)            .getAssignedPackageIdentifiers();    final int N = packageIdentifiers.size();    for (int i = 0; i < N; i++) {        final int id = packageIdentifiers.keyAt(i);        if (id == 0x01 || id == 0x7f) {            continue;        }        rewriteRValues(getClassLoader(), packageIdentifiers.valueAt(i), id);    }    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);    return app;}

可以看到源码中有如下判断:

if (mApplication != null) {    return mApplication;}

正是因为每个App中只有一个Application的实例。接下来可以看到创建Application的代码:

app = mActivityThread.mInstrumentation.newApplication(        cl, appClass, appContext);

最终仍然是进入到Instrumentation中,继续跟踪:

/** * Perform instantiation of the process's {@link Application} object.  The * default implementation provides the normal system behavior. *  * @param cl The ClassLoader with which to instantiate the object. * @param className The name of the class implementing the Application *                  object. * @param context The context to initialize the application with *  * @return The newly instantiated Application object. */public Application newApplication(ClassLoader cl, String className, Context context)        throws InstantiationException, IllegalAccessException,         ClassNotFoundException {    return newApplication(cl.loadClass(className), context);}

继续调用如下方法:

/** * Perform instantiation of the process's {@link Application} object.  The * default implementation provides the normal system behavior. *  * @param clazz The class used to create an Application object from. * @param context The context to initialize the application with *  * @return The newly instantiated Application object. */static public Application newApplication(Class<?> clazz, Context context)        throws InstantiationException, IllegalAccessException,         ClassNotFoundException {    Application app = (Application)clazz.newInstance();    app.attach(context);    return app;}

同样,Application也是通过类加载器来创建是个实例对象。

当Application创建完成之后,会调用如下代码:

instrumentation.callApplicationOnCreate(app);

查看位于Instrumentation的具体实现:

/** * Perform calling of the application's {@link Application#onCreate} * method.  The default implementation simply calls through to that method. * * 

Note: This method will be called immediately after {@link #onCreate(Bundle)}. * Often instrumentation tests start their test thread in onCreate(); you * need to be careful of races between these. (Well between it and * everything else, but let's start here.) * * @param app The application being created. */public void callApplicationOnCreate(Application app) { app.onCreate();}

最终调用app.onCreate()从而触发Application的onCreate生命周期回调,到这里我们就非常熟悉了。

3.当Activity创建完成后,还需要为其创建相关的上下文对象:

Context appContext = createBaseContextForActivity(r, activity);

然后为其创建window对象:

Window window = null;if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {    window = r.mPendingRemoveWindow;    r.mPendingRemoveWindow = null;    r.mPendingRemoveWindowManager = null;}

之后调用Activity的attach方法,将上下文对象、window等附加到Activity上。

activity.attach(appContext, this, getInstrumentation(), r.token,        r.ident, app, r.intent, r.activityInfo, title, r.parent,        r.embeddedID, r.lastNonConfigurationInstances, config,        r.referrer, r.voiceInteractor, window);

注意上述方法的第三个参数,getInstrumentation()返回的是ActivityThread的mInstrumentation实例。还记得之前遗留的问题:Activity的attach是何时调用的吗?到现在答案已经知道了。

Activity A启动Activity B,使用的是A的mInstrumentation,B创建完成,调用attach之后,B也就有了mInstrumentation,mInstrumentation变量在Activity中的声明为:

// set by the thread after the constructor and before onCreate(Bundle savedInstanceState) is called.private Instrumentation mInstrumentation;

根据注释可知,它是在构造函数之后、onCreate之前赋值的,就是上述attach方法。

attach之后,还可能为Activity设置主题:

int theme = r.activityInfo.getThemeResource();if (theme != 0) {    activity.setTheme(theme);}

接下来就会调用mInstrumentation.callActivityOnCreate,在Instrumentation的一种重载方法为:

/** * Perform calling of an activity's {@link Activity#onCreate} * method.  The default implementation simply calls through to that method. * * @param activity The activity being created. * @param icicle The previously frozen state (or null) to pass through to onCreate(). */public void callActivityOnCreate(Activity activity, Bundle icicle) {    prePerformCreate(activity);    activity.performCreate(icicle);    postPerformCreate(activity);}

其中activity.performCreate(icicle)会调用到Activity中的对应方法:

final void performCreate(Bundle icicle) {    restoreHasCurrentPermissionRequest(icicle);    onCreate(icicle);    mActivityTransitionState.readState(icicle);    performCreateCommon();}

其中onCreate(icicle)会触发Activity的onCreate生命周期回调,至此Activity的启动流程大家就非常熟悉了,不再赘述。

Instrumentation源码中除了本小节之前的内容,其他主要就是跟Activity生命周期相关的逻辑,除了上述分析的启动逻辑,还有onStart()、onPause()、onResume()、onStop()、onDestroy()等过程,就不在一一分析。

ActivityThread中的Instrumentation是何时初始化的

Instrumentation在ActivityThread中的声明如下:

Instrumentation mInstrumentation;

从前文的分析可知,Activity创建之后调用attach方法中传入的Instrumentation就是ActivityThread中的,那么在ActivityThread中的Instrumentation是何时初始化的呢?

在ActivityThread中搜索,发现有几处为mInstrumentation赋值的地方:

1.ActivityThread的attach方法,方法声明为:

private void attach(boolean system) {  ……}

当system参数为true时,会执行到如下为mInstrumentation赋值的代码:

try {    mInstrumentation = new Instrumentation();    ContextImpl context = ContextImpl.createAppContext(            this, getSystemContext().mPackageInfo);    mInitialApplication = context.mPackageInfo.makeApplication(true, null);    mInitialApplication.onCreate();} catch (Exception e) {    throw new RuntimeException(            "Unable to instantiate Application():" + e.toString(), e);}

在主线程ActivityThread的main方法中system参数为false,故此时没有创建Instrumentation对象:

ActivityThread thread = new ActivityThread();thread.attach(false);

2.ActivityThread的handleBindApplication(AppBindData data)方法中,有如下逻辑:

final InstrumentationInfo ii;if (data.instrumentationName != null) {    try {        ii = new ApplicationPackageManager(null, getPackageManager())                .getInstrumentationInfo(data.instrumentationName, 0);    } catch (PackageManager.NameNotFoundException e) {        throw new RuntimeException(                "Unable to find instrumentation info for: " + data.instrumentationName);    }    mInstrumentationPackageName = ii.packageName;    mInstrumentationAppDir = ii.sourceDir;    mInstrumentationSplitAppDirs = ii.splitSourceDirs;    mInstrumentationLibDir = getInstrumentationLibrary(data.appInfo, ii);    mInstrumentedAppDir = data.info.getAppDir();    mInstrumentedSplitAppDirs = data.info.getSplitAppDirs();    mInstrumentedLibDir = data.info.getLibDir();} else {    ii = null;}
// Continue loading instrumentation.if (ii != null) {    final ApplicationInfo instrApp = new ApplicationInfo();    ii.copyTo(instrApp);    instrApp.initForUser(UserHandle.myUserId());    final LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,            appContext.getClassLoader(), false, true, false);    final ContextImpl instrContext = ContextImpl.createAppContext(this, pi);    try {        final 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);    }    final ComponentName component = new ComponentName(ii.packageName, ii.name);    mInstrumentation.init(this, instrContext, appContext, component,            data.instrumentationWatcher, data.instrumentationUiAutomationConnection);    if (mProfiler.profileFile != null && !ii.handleProfiling            && mProfiler.profileFd == null) {        mProfiler.handlingProfiling = true;        final File file = new File(mProfiler.profileFile);        file.getParentFile().mkdirs();        Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);    }} else {    mInstrumentation = new Instrumentation();}

当data.instrumentationName不为null时,即必须在AndroidManifest.xml中声明了Instrumentation标签才行,否则不会执行,此时会构造一个InstrumentationInfo对象ii,接下来会使用类加载器构造一个Instrumentation实例。

如果AndroidManifest.xml中没有声明Instrumentation标签,即data.instrumentationName为null时,则直接通过new来创建一个Instrumentation实例:

mInstrumentation = new Instrumentation();

一般应用都会在ActivityThread启动后,通过此方式创建Instrumentation的实例,该行为在应用其他组件创建之前。在一个应用进程中,各个Activity中的Instrumentation都是由ActivityThread传入的,它们归根溯源是同一个。

Instrumentation总结

通过上述源码梳理,发现Instrumentation是一个非常重要的类,甚至Application、Activity的生命周期都与其相关。它的功能大概可以总结为三个方面:

  1. 参与Application、Activity的生命周期逻辑

  2. 用于Android单元测试

  3. 由于Instrumentation独特的运行时机,对于Application、Activity举足轻重的控制权,因此可以进行一些hook操作,具体可参考以下几篇文章:

    1. Android中Hook Instrumentation的一些思考
    2. 美团Android DEX自动拆包及动态加载简介
    3. Android端应用秒开优化体验

更多相关文章

  1. Android(安卓)-- 资源使用和总结经验分享
  2. 自己遇到的Android虚拟机出现的错误及解决方法【不断更新】
  3. Android(安卓)NDK开发之JNI基础知识
  4. Android使用SharedPreferences实现登录帐号和密码的保存方法简介
  5. Android(安卓)studio开发用startForeground时报错
  6. 【android】只让本应用程序的webview加载网页而不调用外部浏览器
  7. android中使用BitmapFactory的decodeStream()方法解码图片失败问
  8. Imageview.setAdjustViewBounds用法
  9. Android(安卓)BindService

随机推荐

  1. 加载不了php的mysql扩展??
  2. 建站学习(PHP+apache+mysql):1.1 日志详解
  3. 30、PHP7和PHP5有什么区别?
  4. php file_get_content阿拉伯字符
  5. [php入门] 1、从安装开发环境环境到(庄B)做
  6. Laravel 5验证日期为php Y格式。g 2015 ?
  7. php-fpm通过request_slowlog_timeout检查
  8. 有没有办法在php关闭标签后强制换行?>什么
  9. 让Tomcat运行PHP的几种方式
  10. php对象的实现