startActivity()流程分析

startActivity() 流程分析 (SDK源码为28)

当我们从手机桌面点击应用图标时,这时候就会打开我们的应用程序,在这个过程中发生了什么事情,整个流程是怎么样的?我们知道在Android中一个App就相当于一个进程,点击应用icon时就相当于从一个进程跳转到了另一进程。在这里就涉及到了跨进程通讯,Android系统中是通过Binder来实现进程通讯的,是由ActivityThread的内部类ApplicationThread来完成的,这里主要涉及到了三个阶段:

  • 第一阶段:ActivityA 通过Binder通讯告诉 ActivityManagerService要启动ActivityB

  • 第二阶段:ActivityManagerService收到启动ActivityB的消息后,会做一些列的判断和准备工作,比如构造Intent,应用栈的处理,应用进程的创建等工作,然后把任务交给ActivityB所在的进程

  • 第三阶段:ActivityB所在进程收到任务消息后,会创建Activity并调用其生命周期方法

针对Android系统来说,手机桌面也是页面,应用icon是这个页面展示的数据;手机桌面是通过Launcher类来实现的,Launcher继承自Activity,手机厂商自定义桌面都是通过实现Launcher来实现的,我们首先来看它的onClick方法,这里面记录了我们点击应用icon后的操作逻辑:

public void onClick(View v) {
    Object tag = v.getTag();
    
    if (tag instanceof ShortcutInfo) { //点击应用icon
        final Intent intent = ((ShortcutInfo) tag).intent;
        boolean success = startActivitySafely(v, intent, tag);
    } else if (tag instanceof FolderInfo) {//点击文件夹,主要是应用分类
        if (v instanceof FolderIcon) {
            FolderIcon fi = (FolderIcon) v;
            handleFolderClick(fi);
        }
    } else if (v == mAllAppsButton) {//点击显示所有应用icon
        if (isAllAppsVisible()) {
            showWorkspace(true);
        } else {
            onClickAllAppsButton(v);
        }
    }
}

这里我们主要关注点击应用icon的逻辑处理,因为后面两种点击逻辑处理最终都会调用点击应用icon的梳理逻辑,接下来我们进入startActivitySafely()方法

boolean startActivitySafely(View v, Intent intent, Object tag) {
    boolean success = false;
    try {
        success = startActivity(v, intent, tag);
    } catch (ActivityNotFoundException e) {
        Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
        Log.e(TAG, "Unable to launch. tag=" + tag + " intent=" + intent, e);
    }
    return success;
}

这个方法主要对startActivity()进行了一层包装,进行异常处理,然后进入startActivity()

boolean startActivity(View v, Intent intent, Object tag) {
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //在新的任务栈中启动
                    
    try {
        UserHandle user = (UserHandle) intent.getParcelableExtra(ApplicationInfo.EXTRA_PROFILE);
        LauncherApps launcherApps = (LauncherApps)
                this.getSystemService(Context.LAUNCHER_APPS_SERVICE);
        
        if (user == null || user.equals(android.os.Process.myUserHandle())) {
            startActivity(intent, opts.toBundle()); //调用Activity的startActivity()
        } else {
            launcherApps.startMainActivity(intent.getComponent(), user,
                                           intent.getSourceBounds(),
                                           opts.toBundle());
        }
        
        return true;
    } catch (SecurityException e) {
        Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
    }
    return false;
}

这里主要分了两步走,我们首先看Activity#startActivity()

@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
    if (options != null) {
        startActivityForResult(intent, -1, options);
    } else {
        startActivityForResult(intent, -1);
    }
}

Activity#startActivity()重写了父类ContextWrapper的startActivity(),然后调用了startActivityForResult(),传入-1的作用是不需要返回结果

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,@Nullable Bundle options) {
    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());
    }
}

以上代码我只摘抄了主要部分,方便理解,在startActivityForResult中调用了Instrumentation#execStartActivity(),这个Instrumentation是用来监控应用程序和系统交互的,mMainThread.getApplicationThread()是一个IBinder接口,用于实现进程间通讯的。

public ActivityResult execStartActivity(Context who, IBinder contextThread ...) {
    IApplicationThread whoThread = (IApplicationThread) contextThread;
    
    try {
        int result = ActivityTaskManager.getService()
            .startActivity(whoThread, who.getBasePackageName(), intent,
                    intent.resolveTypeIfNeeded(who.getContentResolver()),
                    token, target != null ? target.mEmbeddedID : null,
                    requestCode, 0, null, options);
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
}

可以发现,在这里获取了ActivityAIApplicationThread,然后通过ActivityTaskManager获取了ActivityManagerService,并调用了其startActivity,这一步实现了ActivityAActivityManagerService的过渡,启动ActivityB的任务就交由AMS来实现。

接下来我们来看Server端启动Activity的流程,首先我们进入AMS#startActivity()

public final int startActivity(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
    return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
            resultWho, requestCode, startFlags, profilerInfo, bOptions,
            UserHandle.getCallingUserId());
}
public final int startActivityAsUser() {
    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();
}

在这里我们获取了一个ActivityStarter,然后采用Builder模式设置了一些参数,最后调用了execute;看名字这个ActivityStarter是专门用来启动Activity的,接下来我们进入这个类,查看execute做了什么处理

int execute() {
    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,
                mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
                mRequest.resultWho, mRequest.requestCode, mRequest.callingPid,
                mRequest.callingUid, mRequest.callingPackage, mRequest.realCallingPid,
                mRequest.realCallingUid, mRequest.startFlags, mRequest.activityOptions,
                mRequest.ignoreTargetSecurity, mRequest.componentSpecified,
                mRequest.outActivity, mRequest.inTask, mRequest.reason,
                mRequest.allowPendingRemoteAnimationRegistryLookup);
    }
}

startActivityMayWaitstartActivity中主要做了解析Intent,创建ActivityRecord,创建TaskRecord等工作;最终这两个方法都会调用ActivityStarter#startActivityUnchecked()

private int startActivityUnchecked() {
    //启动Flag计算
    computeLaunchingTaskFlags();
    
    //处理Task和Activity的进站操作
    mTargetStack.startActivityLocked();
    
    //处理栈顶Activity
    mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,mOptions);
}
boolean resumeFocusedStackTopActivityLocked() {

    if (targetStack != null && isFocusedStack(targetStack)) {
        return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
    }
    
    final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
    if (r == null || !r.isState(RESUMED)) {
        mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
    } else if (r.isState(RESUMED)) {
        mFocusedStack.executeAppTransition(targetOptions);
    }
    
    return false;
}

上面几个判断最终都会调用ActivityStack#resumeTopActivityUncheckedLocked

boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
    boolean result = false;
    result = resumeTopActivityInnerLocked(prev, options);
    
    return result;
}

ActivityStack#resumeTopActivityInnerLocked()中会经过一些列的判断,最后调用ActivityStackSupervisor#startSpecificActivityLocked()方法

void startSpecificActivityLocked(ActivityRecord r,boolean andResume, boolean checkConfig) {
    ProcessRecord app = mService.getProcessRecordLocked(r.processName,
            r.info.applicationInfo.uid, true);
    
    if (app != null && app.thread != null) {
        realStartActivityLocked(r, app, andResume, checkConfig);
        return;
    }
    
    mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
            "activity", r.intent.getComponent(), false, false, true);
}

在这里会判断ActivityB所在的应用进程是否存在,如果进程不存在,会先去创建进程,最后会调用realStartActivityLocked,我们再进入ActivityStackSupervisor#realStartActivityLocked(),查看做了什么逻辑

final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
            boolean andResume, boolean checkConfig) throws RemoteException {
    
    // Create activity launch transaction. 创建transaction
    final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,r.appToken);
    
    //添加Callback回调接口,稍后会执行
    clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
        System.identityHashCode(r), 
        r.info,
        mergedConfiguration.getGlobalConfiguration(),
        mergedConfiguration.getOverrideConfiguration(), 
        r.compat,
        r.launchedFromPackage, 
        task.voiceInteractor, 
        app.repProcState, 
        r.icicle,
        r.persistentState, 
        results, 
        newIntents, 
        mService.isNextTransitionForward(),
        profilerInfo));
    
    // Schedule transaction.  执行transaction
    mService.getLifecycleManager().scheduleTransaction(clientTransaction);
}

可以看到最后获取了ClientLifecycleManager,然后执行了scheduleTransaction(),然后进入这个方法

void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
    final IApplicationThread client = transaction.getClient();
    transaction.schedule();
}

在这里Transaction的client,这个client是IApplicationThread类型,这个类是用于进程间通讯的,有可能这里会使用client来和AMS通信,后面会不会使用它,我们向下分析就知道了,最后这个方法执行了transaction.schedule()

public void schedule() throws RemoteException {
    mClient.scheduleTransaction(this);
}

果然这里使用利用client实现了ActivityB所在的进程和AMS所在进程进行通讯,调用了ActivityB所在进程的IApplicationThread的scheduleTransaction(),这里Activity启动任务实现了从AMS到ActivityB所在进程的交接

这下startActivity任务来到第三阶段,AMS通过Binder通信,把启动ActivityB的任务交由ActivityB所在进程处理,ActivityB所在进程的ApplicationThreadscheduleTransaction()方法被调用

@Override
public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
    ActivityThread.this.scheduleTransaction(transaction);
}

在ActivityThread方法中会找不到scheduleTransaction,因为调用的是其父类ClientTransactionHandler#scheduleTransaction()

void scheduleTransaction(ClientTransaction transaction) {
    transaction.preExecute(this);
    sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}

在这个方法中,先调用了preExecute()做了一些预处理工作,然后向ActivityThread所在线程的Handler发送了一条消息EXECUTE_TRANSACTION;这个时候直接查看这个名为H的Handler的handleMessage()做了什么处理逻辑

public void handleMessage(Message msg) {
    case EXECUTE_TRANSACTION:
        final ClientTransaction transaction = (ClientTransaction) msg.obj;
        mTransactionExecutor.execute(transaction);
        if (isSystem()) {
            transaction.recycle();
        }
        break;
}

Handler在收到这条消息后,调用TransactionExecutor#execute()

public void execute(ClientTransaction transaction) {
    executeCallbacks(transaction);
    executeLifecycleState(transaction);
}
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);
    }
}

这里会获取到transaction的所有Callback对象,然后依次执行它们的execute方法,那么这些Callback是什么时候添加的呢?还记得我们创建Transaction的时候么,创建Transaction对象时,我们往里面添加了Callback对象LaunchActivityItem,这里我们只需要查看LaunchActivityItem的execute做了什么处理就行 (LaunchActivityItem是继承自ClientTransactionItem)

public void execute(ClientTransactionHandler client ...) {
    ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
            mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
            mPendingResults, mPendingNewIntents, mIsForward,
            mProfilerInfo, client);
    client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
}

这里调用了ClientTransactionHandler#handleLaunchActivity,其实就是调用的ActivityThread的handleLaunchActivity(),因为ActivityThread是ClientTransactionHandler的实现类

public Activity handleLaunchActivity(ActivityClientRecord r,
            PendingTransactionActions pendingActions, Intent customIntent) {
    WindowManagerGlobal.initialize();
    final Activity a = performLaunchActivity(r, customIntent);
}

首先创建WindowManagerService,进行Window初始化相关操作;然后再调用performLaunchActivity()处理Activity的创建逻辑

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    //第一步:创建Activity的Context
    ContextImpl appContext = createBaseContextForActivity(r);

    //第二步:创建Activity实例
    Activity activity = null;
    java.lang.ClassLoader cl = appContext.getClassLoader();
    activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
    
    //第三步:获取当前进程的application实例
    Application app = r.packageInfo.makeApplication(false, mInstrumentation);
    //LoadedApk的makeApplication
    app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
    
    //第三步:执行Activity的attach方法
    //创建PhoneWindow,设置mWindow#setCallback(),设置mWindowManager,设置mApplication
    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);
    
    //第四步:调用Activity的onCreate()
    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
}

到此从ActivityA到ActivityB的启动流程已经完成,ActivityB成功启动,并调用了其onCreate(),如还需要分析后续流程,就应该是View的绘制流程了

到最后,我们对这个流程做一个总结:

  • 第一步:无论是从桌面点击应用图标启动Activity还是从ActivityA跳转到ActivityB,其本质都是从ActivityA跳转到ActivityB,通过调用startActivity方法,通过Binder机制把启动Activity的任务交由AMS,由Instrumentation调用AMS#startActivity()
  • 第二步:AMS的startActivity()收到任务,经过ActivityStarter,ActivityStack,ActivityStackSupervisor的一系列处理,最终由AMS调用目标Activity所在进程的ApplicationThread的scheduleTransaction()
  • 第三步:在ActivityThread的ApplicationThread收到scheduleTransaction()任务后,经过ActivityThread的一系列处理后调用handleLaunchActivity,进行Activity的创建等一系列工作,最后调用onCreate(),完成Activity的启动
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,738评论 5 472
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,377评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,774评论 0 333
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,032评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,015评论 5 361
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,239评论 1 278
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,724评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,374评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,508评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,410评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,457评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,132评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,733评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,804评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,022评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,515评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,116评论 2 341