1. 程式人生 > >Instrumentation框架分析及其使用

Instrumentation框架分析及其使用

本文旨在從Android系統原始碼出發,簡單梳理Instrumentation框架的行為及邏輯結構,供有興趣的同學一起學習

從am instrument談起

am instrument命令的執行

我們知道,命令列執行Android測試的命令是adb shell am instrument,這個命令是如何調起我們的測試程式碼來進行測試的呢,讓我們從am命令的處理原始碼來開始一步步的檢視吧。

am.java是android系統處理am命令的類,其位於/frameworks/base/cmds/am/src/com/android/commands/am/下,有Android原始碼的同學可以到相關目錄下自行檢視

onRun方法是am處理各個不同命令的分發處,我們可以看到am命令有多種用法,其中am instrumentation命令會呼叫runInstrument()方法

public void onRun() throws Exception {

    mAm = ActivityManagerNative.getDefault();
    if (mAm == null) {
        System.err.println(NO_SYSTEM_ERROR_CODE);
        throw new AndroidException("Can't connect to activity manager; is the system running?"
); } String op = nextArgRequired(); if (op.equals("start")) { runStart(); } else if (op.equals("startservice")) { runStartService(); } else if (op.equals("stopservice")) { runStopService(); } else if (op.equals("force-stop")) { runForceStop(); } else
if (op.equals("kill")) { runKill(); } else if (op.equals("kill-all")) { runKillAll(); } else if (op.equals("instrument")) { runInstrument(); } else if (op.equals("broadcast")) { sendBroadcast(); } else if (op.equals("profile")) { runProfile(); } else if (op.equals("dumpheap")) { runDumpHeap(); } else if (op.equals("set-debug-app")) { runSetDebugApp(); } else if (op.equals("clear-debug-app")) { runClearDebugApp(); } else if (op.equals("bug-report")) { runBugReport(); } else if (op.equals("monitor")) { runMonitor(); } else if (op.equals("hang")) { runHang(); } else if (op.equals("restart")) { runRestart(); } else if (op.equals("idle-maintenance")) { runIdleMaintenance(); } else if (op.equals("screen-compat")) { runScreenCompat(); } else if (op.equals("to-uri")) { runToUri(0); } else if (op.equals("to-intent-uri")) { runToUri(Intent.URI_INTENT_SCHEME); } else if (op.equals("to-app-uri")) { runToUri(Intent.URI_ANDROID_APP_SCHEME); } else if (op.equals("switch-user")) { runSwitchUser(); } else if (op.equals("start-user")) { runStartUserInBackground(); } else if (op.equals("stop-user")) { runStopUser(); } else if (op.equals("stack")) { runStack(); } else if (op.equals("lock-task")) { runLockTask(); } else if (op.equals("get-config")) { runGetConfig(); } else { showError("Error: unknown command '" + op + "'"); } }

以下是runInsturmentation方法的原始碼

private void runInstrument() throws Exception {
    String profileFile = null;
    boolean wait = false;
    boolean rawMode = false;
    boolean no_window_animation = false;
    int userId = UserHandle.USER_CURRENT;
    Bundle args = new Bundle();
    String argKey = null, argValue = null;
    IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
    String abi = null;

    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;
        }
    }

    if (userId == UserHandle.USER_ALL) {
        System.err.println("Error: Can't start instrumentation with user 'all'");
        return;
    }

    String cnArg = nextArgRequired();
    ComponentName cn = ComponentName.unflattenFromString(cnArg);
    if (cn == null) throw new IllegalArgumentException("Bad component name: " + cnArg);

    InstrumentationWatcher watcher = null;
    UiAutomationConnection connection = null;
    if (wait) {
        watcher = new InstrumentationWatcher();
        watcher.setRawOutput(rawMode);
        connection = new UiAutomationConnection();
    }

    float[] oldAnims = null;
    if (no_window_animation) {
        oldAnims = wm.getAnimationScales();
        wm.setAnimationScale(0, 0.0f);
        wm.setAnimationScale(1, 0.0f);
    }

    if (abi != null) {
        final String[] supportedAbis = Build.SUPPORTED_ABIS;
        boolean matched = false;
        for (String supportedAbi : supportedAbis) {
            if (supportedAbi.equals(abi)) {
                matched = true;
                break;
            }
        }

        if (!matched) {
            throw new AndroidException(
                    "INSTRUMENTATION_FAILED: Unsupported instruction set " + abi);
        }
    }

    if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher, connection, userId, abi)) {
        throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString());
    }

    if (watcher != null) {
        if (!watcher.waitForFinish()) {
            System.out.println("INSTRUMENTATION_ABORTED: System has crashed.");
        }
    }

    if (oldAnims != null) {
        wm.setAnimationScales(oldAnims);
    }
}

該方法主要做了這麼幾件事:

  1. 解析引數並處理異常,目前支援的引數為(-w,-p,-r,-e,–no_window_animation,–no-window-animation,–user,–abi)
  2. 獲取測試包名和TestRunner,格式為測試包名/TestRunner
  3. 進行一些引數的邏輯處理(通常沒有使用到,可以暫不關注)
  4. 啟動TestRunner進行測試(mAm.startInstrumentation(cn, profileFile, 0, args, watcher, connection, userId, abi))
  5. 如果附帶了-w引數,會等待至執行完成,否則直接結束處理

各個指令含義解析:

  • -w, 等待執行完成後才返回,否則直接返回(Instrumentation的執行在不同執行緒,不管是否帶該引數都會正確執行)
  • -p, 帶1個引數,將一些配置寫入指定檔案(具體用處還未研究,後續有需要再補充)
  • -r, 輸出原始的資料(具體用處還未研究,後續有需要再補充)
  • -e, 帶兩個引數,將這兩個引數作為鍵值對傳遞給TestRunner,由TestRunner處理(後面會提到)
  • –no_window_animation或–no-window-animation,執行Instrumentation過程中禁用動畫效果,執行完後會恢復
  • –user, 帶1個引數,使用指定的uid執行(具體用處還未研究,後續有需要再補充)
  • –abi, 帶1個引數,使用指定的abi執行(具體用處還未研究,後續有需要再補充)

mAm是一個IActivityManager的物件,呼叫其startInstrumentation方法開始處理Instrumentation,下面我們來看看ActivityManager相關的知識

ActivityManager相關知識

ActivityManager是android框架的一個重要部分,它負責一新ActivityThread程序建立,Activity生命週期的維護,下圖為這幾個類之間的層次關係:

在這張圖中,綠色的部分是在SDK中開放給應用程式開發人員的介面,藍色的部分是一個典型的Proxy模式,紅色的部分是底層的服務實現,是真正的動作執行者。這裡的一個核心思想是Proxy模式,關於代理模式相關知識,請參考(暫卻,後續補上)。以上僅是簡單的介紹了下者幾個類的關係,隨著我們上文的步伐,我們會一點點分析出am命令是如何讓Android系統跑起來測試用例的。

獲取ActivityManager

還記得之前在am命令中啟動Instrumentation的命令麼?對的就是這個mAm.startInstrumentation(cn, profileFile, 0, args, watcher, connection, userId, abi)
其中的mAm為mAm = ActivityManagerNative.getDefault();
接下來便是要研究ActivityManagerNative.getDefault()了:

static public IActivityManager getDefault() {
    return gDefault.get();
}

gDefault的定義是IActivityManager的一個單例物件

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;
    }
};

獲取到名為activity的服務後,呼叫asInterface方法:

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);
}

返回的是一個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;
}

將相關引數寫入打包後呼叫mRemote.transact方法,這個mRemote即初始化ActivityManagerProxy時傳入的IBinder物件,即ServiceManager.getService(“activity”)

public static IBinder getService(String name) {
    try {
        IBinder service = sCache.get(name);
        if (service != null) {
            return service;
        } else {
            return getIServiceManager().getService(name);
        }
    } catch (RemoteException e) {
        Log.e(TAG, "error in getService", e);
    }
    return null;
}

可見ServiceManager會先從sCache快取中檢視是否有對應的Binder物件,有則返回,沒有則呼叫getIServiceManager().getService(name),那麼要獲取這個以activity命名的Service,它是在哪裡建立的呢?通過全域性搜尋,我們找到這個呼叫關係,由於中間的方法實在是太太太太太長了,大家有興趣的自己去看原始碼吧,其呼叫過程如下:zygote->main->new SystemServer().run()->[SystemServer]startBootstrapServices()->[SystemServer]mActivityManagerService.setSystemProcess()->[ActivityManagerService]ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true)

由此可見,這個名為mRemote的Binder對應的是ActivityManagerService,ActivityManagerService的transact方法繼承了Binder的實現:

public final boolean transact(int code, Parcel data, Parcel reply,
        int flags) throws RemoteException {
    if (false) Log.v("Binder", "Transact: " + code + " to " + this);
    if (data != null) {
        data.setDataPosition(0);
    }
    boolean r = onTransact(code, data, reply, flags);
    if (reply != null) {
        reply.setDataPosition(0);
    }
    return r;
}

會呼叫onTransact方法:

public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
        throws RemoteException {
    if (code == SYSPROPS_TRANSACTION) {
        // We need to tell all apps about the system property change.
        ArrayList<IBinder> procs = new ArrayList<IBinder>();
        synchronized(this) {
            final int NP = mProcessNames.getMap().size();
            for (int ip=0; ip<NP; ip++) {
                SparseArray<ProcessRecord> apps = mProcessNames.getMap().valueAt(ip);
                final int NA = apps.size();
                for (int ia=0; ia<NA; ia++) {
                    ProcessRecord app = apps.valueAt(ia);
                    if (app.thread != null) {
                        procs.add(app.thread.asBinder());
                    }
                }
            }
        }

        int N = procs.size();
        for (int i=0; i<N; i++) {
            Parcel data2 = Parcel.obtain();
            try {
                procs.get(i).transact(IBinder.SYSPROPS_TRANSACTION, data2, null, 0);
            } catch (RemoteException e) {
            }
            data2.recycle();
        }
    }
    try {
        return super.onTransact(code, data, reply, flags);
    } catch (RuntimeException e) {
        // The activity manager only throws security exceptions, so let's
        // log all others.
        if (!(e instanceof SecurityException)) {
            Slog.wtf(TAG, "Activity Manager Crash", e);
        }
        throw e;
    }
}

由於statusCode不為SYSPROPS_TRANSACTION會呼叫父類ActivityManagerNative的onTransact方法,方法由於statusCode很多,我們只挑選了符合我們要求的部分的原始碼:

case START_INSTRUMENTATION_TRANSACTION: {
    data.enforceInterface(IActivityManager.descriptor);
    ComponentName className = ComponentName.readFromParcel(data);
    String profileFile = data.readString();
    int fl = data.readInt();
    Bundle arguments = data.readBundle();
    IBinder b = data.readStrongBinder();
    IInstrumentationWatcher w = IInstrumentationWatcher.Stub.asInterface(b);
    b = data.readStrongBinder();
    IUiAutomationConnection c = IUiAutomationConnection.Stub.asInterface(b);
    int userId = data.readInt();
    String abiOverride = data.readString();
    boolean res = startInstrumentation(className, profileFile, fl, arguments, w, c, userId,
            abiOverride);
    reply.writeNoException();
    reply.writeInt(res ? 1 : 0);
    return true;
}

在讀取出相應資料後呼叫startInstrumentation方法,開始執行Instrumentation

啟動Instrumentation

所以回到之前am命令的處理,實際呼叫的是ActivityManagerService的startInstrumentation方法。所以Instrumentation的啟動是由ActivityManagerService.startInstrumentation()方法完成的

public boolean startInstrumentation(ComponentName className,
        String profileFile, int flags, Bundle arguments,
        IInstrumentationWatcher watcher, IUiAutomationConnection uiAutomationConnection,
        int userId, String abiOverride) {
    enforceNotIsolatedCaller("startInstrumentation");
    userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
            userId, false, ALLOW_FULL_ONLY, "startInstrumentation", null);
    // Refuse possible leaked file descriptors
    if (arguments != null && arguments.hasFileDescriptors()) {
        throw new IllegalArgumentException("File descriptors passed in Bundle");
    }

    synchronized(this) {
        InstrumentationInfo ii = null;
        ApplicationInfo ai = null;
        try {
            ii = mContext.getPackageManager().getInstrumentationInfo(
                className, STOCK_PM_FLAGS);
            ai = AppGlobals.getPackageManager().getApplicationInfo(
                    ii.targetPackage, STOCK_PM_FLAGS, userId);
        } catch (PackageManager.NameNotFoundException e) {
        } catch (RemoteException e) {
        }
        if (ii == null) {
            reportStartInstrumentationFailure(watcher, className,
                    "Unable to find instrumentation info for: " + className);
            return false;
        }
        if (ai == null) {
            reportStartInstrumentationFailure(watcher, className,
                    "Unable to find instrumentation target package: " + ii.targetPackage);
            return false;
        }

        int match = mContext.getPackageManager().checkSignatures(
                ii.targetPackage, ii.packageName);
        if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
            String msg = "Permission Denial: starting instrumentation "
                    + className + " from pid="
                    + Binder.getCallingPid()
                    + ", uid=" + Binder.getCallingPid()
                    + " not allowed because package " + ii.packageName
                    + " does not have a signature matching the target "
                    + ii.targetPackage;
            reportStartInstrumentationFailure(watcher, className, msg);
            throw new SecurityException(msg);
        }

        final long origId = Binder.clearCallingIdentity();
        // Instrumentation can kill and relaunch even persistent processes
        forceStopPackageLocked(ii.targetPackage, -1, true, false, true, true, false, userId,
                "start instr");
        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);
    }

    return true;
}

該方法做了如下的事情:

  • 檢查TestRunner是否存在
  • 檢查TargetPackage是否存在
  • 檢測簽名是否一致
  • 強制關閉被測包
  • 通過addAppLocked方法建立ProcessRecord

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();
    }

    // This package really, really can not be stopped.
    try {
        AppGlobals.getPackageManager().setPackageStoppedState(
                info.packageName, false, UserHandle.getUserId(app.uid));
    } catch (RemoteException e) {
    } catch (IllegalArgumentException e) {
        Slog.w(TAG, "Failed trying to unstop package "
                + info.packageName + ": " + e);
    }

    if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
            == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
        app.persistent = true;
        app.maxAdj = ProcessList.PERSISTENT_PROC_ADJ;
    }
    if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
        mPersistentStartingProcesses.add(app);
        startProcessLocked(app, "added application", app.processName, abiOverride,
                null /* entryPoint */, null /* entryPointArgs */);
    }

    return app;
}

之後會呼叫startProcessLocked方法啟動程序,啟動程序的過程就比較複雜了,暫時不去分析了,具體呼叫流程如下:startProcessLocked->Process.start->startViaZygote->zygoteSendArgsAndGetResult,zygoteSendArgsAndGetResult函式最終實現的,是向socket服務端寫書據,把建立程序的請求通過socket通訊方式讓framework的程序孵化類zygote建立新程序。而資料就是argsForZygote(一個以字串List形式的把Process.start()所有呼叫引數都包含在裡面的變數),具體的啟動過程可以參考:android程序建立分析

socket服務端收到建立新程序的請求,ZygoteConnection.runOnce()接收到新程序的引數,然後呼叫Zygote.forkAndSpecialize()來fork一個子程序,在子程序中會接著關閉socket,呼叫ZygoteInit.invokeStaticMain(cloader, className, mainArgs),即呼叫ActivityThread.main()。 新的應用程序會從ActivityThread 的 main()函式處開始執行。

ActivityThread,新的程序

首先來看入口,main函式:

public static void main(String[] args) {
    SamplingProfilerIntegration.start();

    // CloseGuard defaults to true and can be quite spammy.  We
    // disable it here, but selectively enable it later (via
    // StrictMode) on debug builds, but using DropBox, not logs.
    CloseGuard.setEnabled(false);

    Environment.initForCurrentUser();

    // Set the reporter for event logging in libcore
    EventLogger.setReporter(new EventLoggingReporter());

    Security.addProvider(new AndroidKeyStoreProvider());

    // Make sure TrustedCertificateStore looks in the right place for CA certificates
    final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
    TrustedCertificateStore.setDefaultUserDirectory(configDir);

    Process.setArgV0("<pre-initialized>");

    Looper.prepareMainLooper();

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

    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }

    if (false) {
        Looper.myLooper().setMessageLogging(new
                LogPrinter(Log.DEBUG, "ActivityThread"));
    }

    Looper.loop();

    throw new RuntimeException("Main thread loop unexpectedly exited");
}

我們看到main方法初始化了主執行緒的訊息佇列,例項化了一個ActivityThread物件,然後呼叫了它的attach方法:

private void attach(boolean system) {
    sCurrentActivityThread = this;
    mSystemThread = system;
    if (!system) {
        ViewRootImpl.addFirstDrawHandler(new Runnable() {
            @Override
            public void run() {
                ensureJitEnabled();
            }
        });
        android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                                                UserHandle.myUserId());
        RuntimeInit.setApplicationObject(mAppThread.asBinder());
        final IActivityManager mgr = ActivityManagerNative.getDefault();
        try {
            mgr.attachApplication(mAppThread);
        } catch (RemoteException ex) {
            // Ignore
        }
        // Watch for getting close to heap limit.
        BinderInternal.addGcWatcher(new Runnable() {
            @Override public void run() {
                if (!mSomeActivitiesChanged) {
                    return;
                }
                Runtime runtime = Runtime.getRuntime();
                long dalvikMax = runtime.maxMemory();
                long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();
                if (dalvikUsed > ((3*dalvikMax)/4)) {
                    if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024)
                            + " total=" + (runtime.totalMemory()/1024)
                            + " used=" + (dalvikUsed/1024));
                    mSomeActivitiesChanged = false;
                    try {
                        mgr.releaseSomeActivities(mAppThread);
                    } catch (RemoteException e) {
                    }
                }
            }
        });
    } else {
        // Don't set application object here -- if the system crashes,
        // we can't display an alert, we just want to die die die.
        android.ddm.DdmHandleAppName.setAppName("system_process",
                UserHandle.myUserId());
        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);
        }
    }

    // add dropbox logging to libcore
    DropBox.setReporter(new DropBoxReporter());

    ViewRootImpl.addConfigCallback(new ComponentCallbacks2() {
        @Override
        public void onConfigurationChanged(Configuration newConfig) {
            synchronized (mResourcesManager) {
                // We need to apply this change to the resources
                // immediately, because upon returning the view
                // hierarchy will be informed about it.
                if (mResourcesManager.applyConfigurationToResourcesLocked(newConfig, null)) {
                    // This actually changed the resources!  Tell
                    // everyone about it.
                    if (mPendingConfiguration == null ||
                            mPendingConfiguration.isOtherSeqNewer(newConfig)) {
                        mPendingConfiguration = newConfig;

                        sendMessage(H.CONFIGURATION_CHANGED, newConfig);
                    }
                }
            }
        }
        @Override
        public void onLowMemory() {
        }
        @Override
        public void onTrimMemory(int level) {
        }
    });
}

我們看到由於是非系統初始化(不是系統啟動時啟動的程序),傳入的引數為false,我們重點關注前面一半的邏輯。這裡又出現了

final IActivityManager mgr = ActivityManagerNative.getDefault();

有了之前的經驗我們已經知道這是指向的ActivityManagerService,然後呼叫了

mgr.attachApplication(mAppThread);

呼叫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);
    }
}

接著走到attachApplicationLocked,這個方法比較長,為了節約篇幅,不貼原始碼了,會呼叫ActivityThread的bindApplication方法

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(app.isolated),
        mCoreSettingsObserver.getCoreSettingsLocked());

而bindApplication做的事情是資料繫結併發送訊息(原始碼部分節選)

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);

在handleMessage方法中可以看到接到Message後的處理

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;

handleBindApplication方法實在是太長了,我們就擷取和Instrumentation相關的部分吧

if (data.instrumentationName != null) {
    InstrumentationInfo ii = null;
    try {
        ii = appContext.getPackageManager().
            getInstrumentationInfo(data.instrumentationName, 0);
    } catch (PackageManager.NameNotFoundException e) {
    }
    if (ii == null) {
        throw new RuntimeException(
            "Unable to find instrumentation info for: "
            + data.instrumentationName);
    }

    mInstrumentationPackageName = ii.packageName;
    mInstrumentationAppDir = ii.sourceDir;
    mInstrumentationSplitAppDirs = ii.splitSourceDirs;
    mInstrumentationLibDir = ii.nativeLibraryDir;
    mInstrumentedAppDir = data.info.getAppDir();
    mInstrumentedSplitAppDirs = data.info.getSplitAppDirs();
    mInstrumentedLibDir = data.info.getLibDir();

    ApplicationInfo instrApp = new ApplicationInfo();
    instrApp.packageName = ii.packageName;
    instrApp.sourceDir = ii.sourceDir;
    instrApp.publicSourceDir = ii.publicSourceDir;
    instrApp.splitSourceDirs = ii.splitSourceDirs;
    instrApp.splitPublicSourceDirs = ii.splitPublicSourceDirs;
    instrApp.dataDir = ii.dataDir;
    instrApp.nativeLibraryDir = ii.nativeLibraryDir;
    LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
            appContext.getClassLoader(), false, true, false);
    ContextImpl instrContext = ContextImpl.createAppContext(this, pi);

    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);

    if (mProfiler.profileFile != null && !ii.handleProfiling
            && mProfiler.profileFd == null) {
        mProfiler.handlingProfiling = true;
        File file = new File(mProfiler.profileFile);
        file.getParentFile().mkdirs();
        Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
    }

} else {
    mInstrumentation = new Instrumentation();
}

if ((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) != 0) {
    dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();
}

// Allow disk access during application and provider setup. This could
// block processing ordered broadcasts, but later processing would
// probably end up doing the same disk access.
final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
try {
    // If the app is being launched for full backup or restore, bring it up in
    // a restricted environment with the base application class.
    Application app = data.info.makeApplication(data.restrictedBackupMode, null);
    mInitialApplication = app;

    // don't bring up providers in restricted mode; they may depend on the
    // app's custom Application class
    if (!data.restrictedBackupMode) {
        List<ProviderInfo> providers = data.providers;
        if (providers != null) {
            installContentProviders(app, providers);
            // For process that contains content providers, we want to
            // ensure that the JIT is enabled "at some point".
            mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
        }
    }

    // Do this after providers, since instrumentation tests generally start their
    // test thread at this point, and we don't want that racing.
    try {
        mInstrumentation.onCreate(data.instrumentationArgs);
    }
    catch (Exception e) {
        throw new RuntimeException(
            "Exception thrown in onCreate() of "
            + data.instrumentationName + ": " + e.toString(), e);
    }

    try {
        mInstrumentation.callApplicationOnCreate(app);
    } catch (Exception e) {
        if (!mInstrumentation.onException(app, e)) {
            throw new RuntimeException(
                "Unable to create application " + app.getClass().getName()
                + ": " + e.toString(), e);
        }
    }
} finally {
    StrictMode.setThreadPolicy(savedPolicy);
}

方法中首先初始化了mInstrumentation,此處Load的Class即am instrument命令傳入的TestRunner

java.lang