本篇为鸡生蛋系列第三篇文章

  1. Linux input系统数据上报流程
  2. Android InputManager分析
  3. AMS startActivity()
  4. activity显示过程梳理
  5. HomeLauncher启动

startActivity()流程极其复杂,代码庞大,牵扯到的类等也较多,
这里简单讲下流程, 更多的作为个人学习笔记。

点击Launcher图标后,Launcher也是通过startActivity()启动另一应用的,
Launcher本身流程不分析了。

AMS Android9.0
http://androidxref.com/9.0.0_r3/

参考:
Android应用程序的Activity启动过程简要介绍和学习计划
https://blog.csdn.net/luoshen...
Android深入四大组件(六)Android8.0 根Activity启动过程(前篇)
https://blog.csdn.net/itachi8...

问题
ActivityStartController ActivityStarter 是什么?作用?关系?

1. AMS init

frameworks/base/services/java/com/android/server/SystemServer.java
private void startBootstrapServices() {
......
    mActivityManagerService = mSystemServiceManager.startService(
            ActivityManagerService.Lifecycle.class).getService();
    mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
    mActivityManagerService.setInstaller(installer);

2. startActivity --> OnCreate()

frameworks/base/core/java/android/app/ContextImpl.java
有几个方法可startActivity(), 最终都调到ActivityManagerService.java里
eg:

startActivity() --> mMainThread.getInstrumentation().execStartActivity() --> startActivity()/ActivityManagerService.java --> startActivityAsUser()
startActivityAsUser() --> ... startActivityAsUser()/ActivityManagerService.java
startActivityAsUser()/ActivityManagerService.java 
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
        boolean validateIncomingUser) {
    //判断调用者进程是否被隔离   
    enforceNotIsolatedCaller("startActivity");

    userId = mActivityStartController.checkTargetUser(userId, validateIncomingUser,
            Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");

    // TODO: Switch to user app stacks here.
    return mActivityStartController.obtainStarter(intent, "startActivityAsUser")
            .setCaller(caller)
            .setCallingPackage(callingPackage)
            .setResolvedType(resolvedType)
            .setResultTo(resultTo)
            .setResultWho(resultWho)
            .setRequestCode(requestCode)
            .setStartFlags(startFlags)
            .setProfilerInfo(profilerInfo)
            .setActivityOptions(bOptions)
            .setMayWait(userId)
            .execute();

}

这里通过 ActivityStartController 申请了个 ActivityStarter,然后执行
frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java

maywait由上面setMayWait(userId)设置, 然后调用 startActivityMayWait() 或者 startActivity()
执行完后onExecutionComplete()回调ActivityStartController的 onExecutionComplete()执行一些回收任务;

/**
 * Starts an activity based on the request parameters provided earlier.
 * @return The starter result.
 */
int execute() {
    try {
        // TODO(b/64750076): Look into passing request directly to these methods to allow
        // for transactional diffs and preprocessing.
        if (mRequest.mayWait) {
            return startActivityMayWait(mRequest.caller, mRequest.callingUid,
                    mRequest.callingPackage, mRequest.intent, mRequest.resolvedType,
                    mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
                    mRequest.resultWho, mRequest.requestCode, mRequest.startFlags,
                    mRequest.profilerInfo, mRequest.waitResult, mRequest.globalConfig,
                    mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.userId,
                    mRequest.inTask, mRequest.reason,
                    mRequest.allowPendingRemoteAnimationRegistryLookup);
        } else {
            return startActivity(mRequest.caller, mRequest.intent, mRequest.ephemeralIntent,
                    mRequest.resolvedType, mRequest.activityInfo, mRequest.resolveInfo,
......
        }
    } finally {
        onExecutionComplete();
    }

private int startActivityMayWait(IApplicationThread caller, int callingUid,
        String callingPackage, Intent intent, String resolvedType,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        IBinder resultTo, String resultWho, int requestCode, int startFlags,
        ProfilerInfo profilerInfo, WaitResult outResult,
        Configuration globalConfig, SafeActivityOptions options, boolean ignoreTargetSecurity,
        int userId, TaskRecord inTask, String reason,
        boolean allowPendingRemoteAnimationRegistryLookup) {
......
        final ActivityRecord[] outRecord = new ActivityRecord[1];
        int res = startActivity(caller, intent, ephemeralIntent, resolvedType, aInfo, rInfo,
                voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid,
                callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options,
                ignoreTargetSecurity, componentSpecified, outRecord, inTask, reason,
                allowPendingRemoteAnimationRegistryLookup);
......
        if (outResult != null) {
            outResult.result = res;

            final ActivityRecord r = outRecord[0];
            // 根据返回结果进一步处理
            switch(res) {
                case START_SUCCESS: {
......
                case START_DELIVERED_TO_TOP: {
......
                case START_TASK_TO_FRONT: {
......

上面的caller为IApplicationThread
startActivity(IApplicationThread..)也有两个,最终调用到了startActivity(final ActivityRecord r..)

private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
        String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
...... //创建即将要启动的Activity的描述类ActivityRecord
    ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
            callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
            resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
            mSupervisor, checkedOptions, sourceRecord);
......
    return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
            true /* doResume */, checkedOptions, inTask, outActivity);
}
startActivity(IApplicationThread..) --> startActivity(final ActivityRecord r..)
private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
            ActivityRecord[] outActivity) {
    int result = START_CANCELED;
    try {
        mService.mWindowManager.deferSurfaceLayout();
        result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
                startFlags, doResume, options, inTask, outActivity);
    } finally {
......
    }

    postStartActivityProcessing(r, result, mTargetStack);

    return result;
}

private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
        ActivityRecord[] outActivity) {
......

    if (reusedActivity != null) {
        ......
        reusedActivity = setTargetStackAndMoveToFrontIfNeeded(reusedActivity);
.......
    // 注释1 是否要创建新的task
    // Should this be considered a new task?
    int result = START_SUCCESS;
    if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
            && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
        newTask = true;
        // 注释2
        result = setTaskFromReuseOrCreateNewTask(taskToAffiliate, topStack);
    } else if (mSourceRecord != null) {
        result = setTaskFromSourceRecord();
    } else if (mInTask != null) {
        result = setTaskFromInTask();
    } else {
        // This not being started from an existing activity, and not part of a new task...
        // just put it in the top task, though these days this case should never happen.
        setTaskToCurrentTopOrCreateNewTask();
    }
......

    mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,
            mOptions);
    if (mDoResume) {
        final ActivityRecord topTaskActivity =
                mStartActivity.getTask().topRunningActivityLocked();
        if (!mTargetStack.isFocusable()
                || (topTaskActivity != null && topTaskActivity.mTaskOverlay
                && mStartActivity != topTaskActivity)) {
...
            mTargetStack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
            // Go ahead and tell window manager to execute app transition for this activity
            // since the app transition will not be triggered through the resume channel.
            mService.mWindowManager.executeAppTransition();
        } else {
            // If the target stack was not previously focusable (previous top running activity
            // on that stack was not visible) then any prior calls to move the stack to the
            // will not update the focused stack.  If starting the new activity now allows the
            // task stack to be focusable, then ensure that we now update the focused stack
            // accordingly.
            if (mTargetStack.isFocusable() && !mSupervisor.isFocusedStack(mTargetStack)) {
                mTargetStack.moveToFront("startActivityUnchecked");
            }
            mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
                    mOptions);
        }
    } else if (mStartActivity != null) {
        mSupervisor.mRecentTasks.add(mStartActivity.getTask());
    }
    mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);

    mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(), preferredWindowingMode,
            preferredLaunchDisplayId, mTargetStack);

    return START_SUCCESS;
}

在注释1处我们得知,启动根Activity时会将Intent的Flag设置为FLAG_ACTIVITY_NEW_TASK,
这样注释1处的条件判断就会满足,
接着执行注释2处的 setTaskFromReuseOrCreateNewTask(),其内部会创建一个新的TaskRecord,
TaskRecord用来描述一个Activity任务栈,也就是说setTaskFromReuseOrCreateNewTask()内部会创建一个新的Activity任务栈

boolean resumeFocusedStackTopActivityLocked(
        ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
......
    if (targetStack != null && isFocusedStack(targetStack)) {
        return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
    }
......// 注释1 获取要启动的Activity所在栈的栈顶的不是处于停止状态的ActivityRecord
    final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
    if (r == null || !r.isState(RESUMED)) {// 注释2
        mFocusedStack.resumeTopActivityUncheckedLocked(null, null);// 注释3
    } else if (r.isState(RESUMED)) {
        // Kick off any lingering app transitions form the MoveTaskToFront operation.
        mFocusedStack.executeAppTransition(targetOptions);
    }

注释1处调用ActivityStack的topRunningActivityLocked方法获取要启动的Activity所在栈的栈顶的不是处于停止状态的ActivityRecord。
注释2处如果ActivityRecord不为null,或者要启动的Activity的状态不是RESUMED状态,
就会调用注释3处的ActivityStack的resumeTopActivityUncheckedLocked方法,对于即将要启动的Activity,
注释2的条件判断是肯定满足,因此我们来查看ActivityStack的resumeTopActivityUncheckedLocked方法

frameworks/base/services/core/java/com/android/server/am/ActivityStack.java
mFocusedStack.resumeTopActivityUncheckedLocked() --> resumeTopActivityInnerLocked() --> mStackSupervisor.startSpecificActivityLocked(next, true, false);
frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
void startSpecificActivityLocked(ActivityRecord r,
        boolean andResume, boolean checkConfig) {
    // Is this activity's application already running?
    ProcessRecord app = mService.getProcessRecordLocked(r.processName,
            r.info.applicationInfo.uid, true);
....
    if (app != null && app.thread != null) {
......//如果app已经运行,调用realStartActivityLocked()
            realStartActivityLocked(r, app, andResume, checkConfig);
            return;
......
    }
//如果没有运行则调用AMS的startProcessLocked()
    mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
            "activity", r.intent.getComponent(), false, false, true);
}

realStartActivityLocked()为应用程序内部启动非默认Activity的过程,暂时不看,
我们看 startProcessLocked(),
startProcessLocked()函数也有好几个, 最终都会转为 startProcessLocked(ProcessRecord app...
ProcessRecord生成eg:
final ProcessRecord r = new ProcessRecord(this, stats, info, proc, uid);
然后进一步的调用

startProcessLocked(String hostingType,... --> startProcess(app.hostingType...
private ProcessStartResult startProcess(String hostingType, String entryPoint,
        ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
......
        if (hostingType.equals("webview_service")) {
            startResult = startWebView(entryPoint,
                    app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                    app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                    app.info.dataDir, null,
                    new String[] {PROC_START_SEQ_IDENT + app.startSeq});
        } else {
            startResult = Process.start(entryPoint,
                    app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                    app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                    app.info.dataDir, invokeWith,
                    new String[] {PROC_START_SEQ_IDENT + app.startSeq});
        }

如果hostingType为webview_service调用Process.startWebView()
否则 Process.start()

frameworks/base/core/java/android/os/Process.java
* @param processClass The class to use as the process's main entry
*                     point.
public static final ProcessStartResult start(final String processClass,
                              final String niceName,
                              int uid, int gid, int[] gids,
                              int runtimeFlags, int mountExternal,
                              int targetSdkVersion,
                              ......) {
    // 注意 processClass 为 "android.app.ActivityThread"
    return zygoteProcess.start(processClass, niceName, uid, gid, gids,
                runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
}

我们重点关注下传入的参数 processClass,即 entryPoint,通过查找传传下来的参数,即为
final String entryPoint = "android.app.ActivityThread";
新的进程会导入android.app.ActivityThread类,并且执行它的main函数.
zygoteProcess.start()后面有机会再分析,我们就直接看 ActivityThread main()

frameworks/base/core/java/android/app/ActivityThread.java
public static void main(String[] args) {
......
    Looper.prepareMainLooper();

    // Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
    // It will be in the format "seq=114"
    long startSeq = 0;
    if (args != null) {
        for (int i = args.length - 1; i >= 0; --i) {
            if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
                startSeq = Long.parseLong(
                        args[i].substring(PROC_START_SEQ_IDENT.length()));
            }
        }
    }
    ActivityThread thread = new ActivityThread();
    thread.attach(false, startSeq);

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

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

其main函数主要为Looper准备主looper, 创建一个ActivityThread实例,然后调用它的attach函数,
接着就进入消息循环了,若loope退出则抛个异常。
attach()如果为非system则进一步调用AMS attachApplication()

private void attach(boolean system, long startSeq) {
......
    if (!system) {
        final IActivityManager mgr = ActivityManager.getService();
        try {
            mgr.attachApplication(mAppThread, startSeq);

attachApplication()--> attachApplicationLocked()
private final boolean attachApplicationLocked(IApplicationThread thread,
        int pid, int callingUid, long startSeq) {
        } else if (app.instr != null) {
            thread.bindApplication(processName, appInfo, providers,
..
    // See if the top visible activity is waiting to run in this process...
    if (normalMode) {
        try {
            if (mStackSupervisor.attachApplicationLocked(app)) {

thread.bindApplication() 将应用进程的ApplicationThread对象绑定到ActivityManagerService,
也就是说获得ApplicationThread对象的代理对象。

mStackSupervisor.attachApplicationLocked(app)
frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java#
boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
......
            final ActivityRecord top = stack.topRunningActivityLocked();
            final int size = mTmpActivityList.size();
            for (int i = 0; i < size; i++) {
                final ActivityRecord activity = mTmpActivityList.get(i);
                if (activity.app == null && app.uid == activity.info.applicationInfo.uid
                        && processName.equals(activity.processName)) {
                    try {
                        if (realStartActivityLocked(activity, app,
                                top == activity /* andResume */, true /* checkConfig */)) {
......
}

final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
         boolean andResume, boolean checkConfig) throws RemoteException {
.........
             // Create activity launch transaction.
             final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,
                     r.appToken);
             clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent), <----注意这个callback,为LaunchActivityItem
                     System.identityHashCode(r), r.info,
.......
             // Schedule transaction.
             mService.getLifecycleManager().scheduleTransaction(clientTransaction);

Android9引入了ClientLifecycle和ClientTransactionHandler来辅助管理Activity生命周期,过程更麻烦了.

frameworks/base/services/core/java/com/android/server/am/ClientLifecycleManager.java
void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
    final IApplicationThread client = transaction.getClient();
    transaction.schedule(); -->
frameworks/base/core/java/android/app/servertransaction/ClientTransaction.java
private IApplicationThread mClient;
public void schedule() throws RemoteException {
    mClient.scheduleTransaction(this); -->
}
frameworks/base/core/java/android/app/ActivityThread.java
private class ApplicationThread extends IApplicationThread.Stub {
......
     @Override
     public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
         ActivityThread.this.scheduleTransaction(transaction); -->
     }

ActivityThread类中并没有定义scheduleTransaction方法,所以调用的是他父类ClientTransactionHandler的 scheduleTransaction()。

frameworks/base/core/java/android/app/ClientTransactionHandler.java
void scheduleTransaction(ClientTransaction transaction) {
    transaction.preExecute(this);
    sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}

Handler接到后

frameworks/base/core/java/android/app/ActivityThread.java
public void handleMessage(Message msg) {
        case EXECUTE_TRANSACTION:
            final ClientTransaction transaction = (ClientTransaction) msg.obj;
            mTransactionExecutor.execute(transaction); -->
frameworks/base/core/java/android/app/servertransaction/TransactionExecutor.java
public void execute(ClientTransaction transaction) {
......
    executeCallbacks(transaction);

    executeLifecycleState(transaction);

上面会执行callback函数,然后再执行executeLifecycleState()
这里我们只看callback函数,注意
realStartActivityLocked()传入的callback为LaunchActivityItem

public void executeCallbacks(ClientTransaction transaction) {
    final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
......
    final int size = callbacks.size();
    for (int i = 0; i < size; ++i) {
        final ClientTransactionItem item = callbacks.get(i);
......
        item.execute(mTransactionHandler, token, mPendingActions); -->
        item.postExecute(mTransactionHandler, token, mPendingActions);
......
}

item.execute() 即调用到LaunchActivityItem.execute()

frameworks/base/core/java/android/app/servertransaction/LaunchActivityItem.java
execute() --> client.handleLaunchActivity -->
ActivityThread.java handleLaunchActivity() --> performLaunchActivity()

在ActivityThread.performLaunchActivity方法中首先对Activity的ComponentName、ContextImpl、Activity
以及Application对象进行了初始化并相互关联,
然后设置Activity主题,最后调用Instrumentation.callActivityOnCreate方法。

/**  Core implementation of activity launch. */
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
......//初始化ComponentName
    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);
    }
    //初始化ContextImpl
    ContextImpl appContext = createBaseContextForActivity(r);
    Activity activity = null;
    try {
        java.lang.ClassLoader cl = appContext.getClassLoader();
        //初始化activity
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);
       ......
    }

    try {//初始化Application
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);
......
        if (activity != null) {
....... //关联
            appContext.setOuterContext(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, r.configCallback);

......//调用callActivityOnCreate
            if (r.isPersistable()) {
                mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
            } else {
                mInstrumentation.callActivityOnCreate(activity, r.state);
            }
......
        }
        //状态设为ON_CREATE
        r.setState(ON_CREATE);
......
    return activity;
}
mInstrumentation.callActivityOnCreate() --> activity.performCreate -->
frameworks/base/core/java/android/app/Activity.java
final void performCreate(Bundle icicle, PersistableBundle persistentState) {
......
    if (persistentState != null) {
        onCreate(icicle, persistentState);
    } else {
        onCreate(icicle);
    }
......
}

即最终调用到了我们的应用程序的onCreate()

流程图,打开
https://www.websequencediagra...
然后复制粘贴下面的内容

Title Androd9 startActivity->OnCreate流程

participant ContextImpl
participant Instrumentation
participant ActivityManagerService
participant ActivityStartController
participant ActivityStarter
participant ActivityStack
participant ActivityStackSupervisor
participant Process
participant zygoteProcess
participant ActivityThread


opt startActivity part1
    ContextImpl->+Instrumentation:startActivity() --> mMainThread.getInstrumentation()
        Instrumentation->ActivityManagerService:execStartActivity()
        ActivityManagerService->ActivityStartController:startActivityAsUser()
        ActivityStartController->ActivityStarter:obtainStarter()
        ActivityStarter->ActivityStarter:execute()
        ActivityStarter->ActivityStarter:startActivityMayWait()/startActivity(IApplicationThread...)
        ActivityStarter->ActivityStarter:startActivity(IApplicationThread...)
        ActivityStarter->ActivityStarter:startActivity(ActivityRecord...)
        ActivityStarter->+ActivityStarter:startActivityUnchecked(ActivityRecord...)
            ActivityStarter->ActivityStarter:setTaskFromReuseOrCreateNewTask()
            ActivityStarter->ActivityStackSupervisor:resumeFocusedStackTopActivityLocked()
            ActivityStackSupervisor->ActivityStack:resumeTopActivityInnerLocked()
            ActivityStack->ActivityStackSupervisor:startSpecificActivityLocked()
            alt if (app.thread != null)
                ActivityStackSupervisor->ActivityStackSupervisor:realStartActivityLocked()
            else
                ActivityStackSupervisor->ActivityManagerService:startProcessLocked()
            end
            ActivityManagerService->ActivityManagerService:startProcessLocked(ProcessRecord app...
            ActivityManagerService->ActivityManagerService:startProcessLocked(String hostingType,...
            ActivityManagerService->ActivityManagerService:startProcess(app.hostingType...
            alt 如果hostingType为webview_service
                ActivityManagerService->Process:startWebView()
            else
                ActivityManagerService->Process:start("android.app.ActivityThread"...)
            end
end

opt startActivity part2
            Process->zygoteProcess:start() 
            zygoteProcess->ActivityThread:...->android.app.ActivityThread main()

            note right of ActivityThread
                Looper.prepareMainLooper();
                ActivityThread thread = new ActivityThread();
                thread.attach(false, startSeq);
                Looper.loop();
            end note
end

Atom
26 声望30 粉丝

带着问题看code