美文网首页Android
界面显示_Activity启动流程

界面显示_Activity启动流程

作者: gczxbb | 来源:发表于2018-02-27 22:18 被阅读5次

    前言

    从一个简单Android视图切入,探索Android平台显示流程。剖析从Activity启动到界面完全显示过程中发生的故事,从而对Android框架层知识有一个初步了解。

    参考源码


    启动Activity组件

    Intent intent = new Intent(mActivity.this, xActivity.class);
    startActivityForResult(intent, requestCode);
    

    通过Activity#startActivityForResult启动Activity组件,Intent是启动意图,包含被启动Activity类组件,传递的数据。
    Activity#startActivityForResult方法

    public void startActivityForResult(Intent intent, int requestCode, 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());
        ...
        if (requestCode >= 0) { 
             mStartedActivity = true;
        }
        cancelInputsAndStartExitTransition(options);
        ...
    }
    

    Activity对象内部有一个Instrumentation,Activity#attach时赋值初始化,对象保存在ActivityThread,在ActivityThread#handleBindApplicationActivity创建。
    Instrumentation#execStartActivity方法。

    public ActivityResult execStartActivity(Context who, IBinder contextThread,
               IBinder token, Activity target,
               Intent intent, int requestCode, Bundle options){
        IApplicationThread whoThread = (IApplicationThread) contextThread;
        ...
        try {
            ...
            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;
    }
    

    Instrumentation#execStartActivity方法负责和system_sever系统服务进程通信,AMS提供服务。
    向AMS传递参数如下表所示

    主要参数 功能
    IApplicationThread whoThread Binder,App进程ApplicationThread,封装在ActivityThread。
    Intent 启动意图。
    Context who.getBasePackageName() who是当前发起者,发起者的上下文的包名。
    IBinder token 发起者Activity内部IBinder,attach时初始化赋值,代表发起者组件。
    requestCode 发起者请求code。
    Bundle 传递参数,key-value

    IApplicationThread定义系统服务进程访问App进程的业务逻辑。每个Activity都包含ActivityThread,通过ActivityThread#getApplicationThread()获取ApplicationThread对象。

    ActivityThread与ApplicationThread.png

    Context who代表当前发起者,如果在Activity组件启动另一个Activity,who代表Activity。
    IBinder token在Activity#attach方法中被赋值,在发起者Activity被启动,AMS回调App方法ApplicationThread#scheduleLaunchActivity时回传的token。当发起者Activity启动另一个Activity时,带着token。

    启动Activity组件的主要逻辑由系统服务进程的AMS服务完成,App进程通过AMS代理调用ServiceApi方法请求服务,线程休眠等待结果

    system_server进程开启一个Binder线程处理请求,处理过程中会回调App进程,同样是App开启Binder线程处理system_server进程请求,此时休眠的App主线程不受影响,仍等待。

    ApplicationThread负责处理AMS回调App进程的业务逻辑,大部分服务方法仅发送一个消息到App主线程消息队列,并无其他耗时操作,对AMS的Binder线程来说,休眠时间不会长,在处理业务时中间休息一下告诉App主线程一个消息
    AMS的Binder线程不会有太多耗时操作逻辑,及时返回App主线程结果,防止App主线程阻塞时间过长。

    结果返回,发起者负责启动的任务结束,暂停上一个(如果存在)活动Activity以及开启新Activity生命周期的任务将继续从主线程消息队列里获取消息去执行。


    AMS服务处理Activity组件启动

    App进程中启动Activity与AMS的交互流程图


    一个普通Activity的启动流程图_AMS服务流程.png

    从上图看出,AMS中启动Activity组件入口AMS#startActivity,依次调用startActivityMayWait、startActivityLocked、startActivityUncheckedLocked等,涉及两个类ActivityStackSupervisor与ActivityStack。

    Activity启动模式默认是standard

    • 1:ActivityStackSupervisor#startActivityLocked中,根据传入的App进程IApplicationThread解析ProcessRecord,每个App进程都通过IApplicationThread与AMS中的一个ProcessRecord对应。
      ActivityStackSupervisor#startActivityLocked方法代码段
    ProcessRecord callerApp = null;
    if (caller != null) {//caller是IApplicationThread caller
        callerApp = mService.getRecordForAppLocked(caller);
        if (callerApp != null) {
            callingPid = callerApp.pid;
            callingUid = callerApp.info.uid;
        } else {
            err = ActivityManager.START_PERMISSION_DENIED;
        }
    }
    

    ProcessRecord代表在AMS中存储一条进程记录。

    根据传入的IBinder token解析发起者Activity在AMS中存储的ActivityRecord,作为接收结果的ActivityRecord。
    ActivityStackSupervisor#startActivityLocked方法代码段

    ActivityRecord sourceRecord = null;
    ActivityRecord resultRecord = null;
    if (resultTo != null) {//resultTo是IBinder resultTo
        sourceRecord = isInAnyStackLocked(resultTo);
        if (sourceRecord != null) {
            if (requestCode >= 0 && !sourceRecord.finishing) {
                 resultRecord = sourceRecord;
            }
        }
    }
    

    遍历ActivityDisplay集合,在ActivityDisplay中ArrayList<ActivityStack> mStacks中查找,mStacks是一个ActivityStack栈列表。遍历每项ActivityStack,从ActivityStack中查找符合token的ActivityRecord。

    ActivityDisplay的ActivityStack列表.png

    IBinder转换Token业务类型,从Token内部获取弱引用ActivityRecord,判断ActivityRecord是否在某个ActivityStack中。

    每个启动的Activity在AMS中对应一个ActivityRecord记录。

    • 2:从Intent中解析Flags,启动时未设置默认是0。
    final int launchFlags = intent.getFlags();
    
    • 3:创建ActivityRecord,在内部做很多初始化工作,如解析启动模式。
      ActivityStackSupervisor#startActivityLocked方法代码段
    ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
                    intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
                    requestCode, componentSpecified, voiceSession != null, this, container, options);
    

    ActivityRecord构造方法中创建Token对象,内部弱引用ActivityRecord,用于传递给App进程,存储在Activity中。
    ActivityStackSupervisor#startActivityLocked方法代码段

    err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
                    startFlags, true, options, inTask);
    

    触发startActivityUncheckedLocked方法,传入新建的ActivityRecord与发起者ActivityRecord。

    • 4:ActivityStackSupervisor#startActivityUncheckedLocked中,确定ActivityStack栈

    启动模式在ActivityInfo,ActivityRecord构造方法时将lauchMode存储到ActivityRecord内。

    ActivityStackSupervisor#startActivityUncheckedLocked方法代码段

    final boolean launchSingleTop = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP;
    final boolean launchSingleInstance = r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE;
    final boolean launchSingleTask = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK;
    ....
    if (r.resultTo == null && inTask == null && !addingToTask
                    && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
        newTask = true;
        targetStack = computeStackFocus(r, newTask);
        targetStack.moveToFront("startingNewTask");
    } else if (sourceRecord != null) {
        //sourceRecord发起者不空,走这里的代码。
        final TaskRecord sourceTask = sourceRecord.task;
        ...
        targetStack = sourceTask.stack;    
        ...
        r.setTask(sourceTask, null);
    } else if (inTask != null) {
        ....
        targetStack = inTask.stack;
        r.setTask(inTask, null);
    } else {
        targetStack = computeStackFocus(r, newTask);
        targetStack.moveToFront("addingToTopTask");
        ActivityRecord prev = targetStack.topActivity();
        r.setTask(prev != null ? prev.task : targetStack.createTaskRecord(getNextTaskId(),
                                r.info, intent, null, null, true), null);
        ...
    }
    ...
    targetStack.mLastPausedActivity = null;
    targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);
    

    入参doResume是true。
    sourceRecord发起者不空时,新ActivityRecord的TaskRecord和发起者ActivityRecord保持一致,新ActivityRecord设置TaskRecord,并获取TaskRecord内部的ActivityStack栈。
    前期工作寻找目标栈targetStack,在得到目标栈ActivityStack后,将触发ActivityStack的startActivityLocked方法。

    根据不同的情况获取目标栈。当Intent存在FLAG_ACTIVITY_NEW_TASK标志时,createTaskRecord新建TaskRecord。

    TaskRecord、ActivityStack、ActivityRecord的关系图如下:

    ActivityRecord、ActivityStack和TaskRecord的关系 (1).png

    ActivityStack栈中有一个TaskRecord列表mTaskHistory,每一项TaskRecord内部有ActivityStack。
    TaskRecord中有一个ActivityRecord列表mActivities,每一项ActivityRecord内部有TaskRecord。

    ActivityRecord关联TaskRecord,TaskRecord关联ActivityStack。

    TaskRecord、ActivityStack、ActivityRecord图


    ActivityRecord.png

    从上图中可知这里有两个ActivityStack,一个存放系统UI相关的ActivityStack,另一个存放App的TaskRecord。开启了四个应用,两个自己编译的App,两个手机系统App。如图对应四个TaskRecord,自己的App启动三个Activity,存储在TaskRecord的mActivitys中。

    ActivityStackSupervisor#startActivityUncheckedLocked方法启动模式singleTop处理代码段

    ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(notTop);
    if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) {//同一个Activity类
        if (top.app != null && top.app.thread != null) {
            if ((launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
                                || launchSingleTop || launchSingleTask) {
                topStack.mLastPausedActivity = null;
                if (doResume) {
                    resumeTopActivitiesLocked();
                }
                ...
                top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
                return ActivityManager.START_DELIVERED_TO_TOP;
            }
        }
    }
    

    满足top的realActivity与新ActivityRecord的realActivity相等 ,说明最上面的组件与新组件的组件类名相同,是同一个Activity。
    当launchSingleTop是true时,不用确定ActivityStack栈,也不需addActivityToTop方法将ActivityRecord加入到ActivityStack的TaskRecord中,直接调用resumeTopActivitiesLocked方法。
    ActivityStack#resumeTopActivityInnerLocked代码段

    if (mResumedActivity == next && next.state == ActivityState.RESUMED &&
                        mStackSupervisor.allResumedActivitiesComplete()) {
        ...
        return false;
    }
    

    mResumedActivity与最上面栈顶next相同,返回。因为新ActivityRecord未addActivityToTop加入,因此next还是以前的,与当前活跃的mResumedActivity相等。

    配置了singleTop启动模式Activity组件,如果栈顶最上层已经存在该Activity,将不会再启动一次。

    ActivityStackSupervisor#startActivityUncheckedLocked方法启动模式singleTask处理代码段

    if ((launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
                                == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) {
        ...
        } else if ((launchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
                                || launchSingleInstance || launchSingleTask) {        
        //将最上面ActivityRecord对应task的部分内容清理。
        ActivityRecord top = intentActivity.task.performClearTaskLocked(r, launchFlags);    
        ...
    } else if (){
    
    }
    

    找到ActivityRecord对应的TaskRecord,清理内部部分mActivitys,从后向前遍历,如果发现一个ActivityRecord与当前新建的ActivityRecord的组件名相同,finishActivityLocked将他们中间的一些Activity清理,最后Resume发现的那个ActivityRecord。

    配置了singleTask启动模式Activity组件,如果栈中已经存在该Activity,将不会再启动一次,将顶部的所有Activity清除。

    • 5:触发ActivityStack#startActivityLocked方法,newTask表示是否需新建TaskRecord,与启动模式与FLAG_ACTIVITY_NEW_TASK等相关,这里不需新建。

    ActivityStack#startActivityLocked方法

    final void startActivityLocked(ActivityRecord r, boolean newTask,
                                   boolean doResume, boolean keepCurTransition, Bundle options) {
        TaskRecord rTask = r.task;
        final int taskId = rTask.taskId;
        if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) {
    
            insertTaskAtTop(rTask, r);
            mWindowManager.moveTaskToTop(taskId);
        }
        TaskRecord task = null;
        if (!newTask) {
            //遍历mTaskHistory中的TaskRecord 
            boolean startIt = true;
            for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
                task = mTaskHistory.get(taskNdx);
                if (task.getTopActivity() == null) {
                    //TaskRecord 所有Activity全部finish,跳过继续
                    continue;
                }
                //与ActivityRecord关联的TaskRecord一致。
                if (task == r.task) {
                    if (!startIt) {
                        ....
                        return;
                    }
                    break;
                } else if (task.numFullscreen > 0) {
                    startIt = false;
                }
            }
        }
        ...
        task = r.task;
        task.addActivityToTop(r);
        task.setFrontOfTask();
    
        r.putInHistory();
        if (!isHomeStack() || numActivities() > 0) {
            boolean showStartingIcon = newTask;
            ProcessRecord proc = r.app;
            if (proc == null) {
                proc = mService.mProcessNames.get(r.processName, r.info.applicationInfo.uid);
            }
            if (proc == null || proc.thread == null) {
                showStartingIcon = true;
            }
            ....
            mWindowManager.addAppToken(task.mActivities.indexOf(r),
                    r.appToken, r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
                    (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId,
                    r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind);
            boolean doShow = true;
            ...
            ...
        } else {
            ...
        }
    
        if (doResume) {
            mStackSupervisor.resumeTopActivitiesLocked(this, r, options);
        }
    }
    

    ActivityRecord关联的TaskRecord,将ActivityRecord加入到TaskRecord中列表mActivities的尾部
    调用WMS#addAppToken方法,为Activity组件界面提前注入窗体Token
    最后,因doResume是true,触发ActivityStackSupervisor监管者的resumeTopActivitiesLocked方法。

    判断传入的this即targetStack是不是Top的ActivityStack。

    触发ActivityStack的resumeTopActivityInnerLocked方法。

    • 6:ActivityStack#resumeTopActivityInnerLocked的工作是负责让ActivityStack栈中最Top的ActivityRecord记录Resume

    最上面ActivityRecord即next通过topRunningActivityLocked获取,此时mResumedActivity保存的仍是上一个ActivityRecord,与最上面的next不同。通过startPausingLocked方法让该ActivityRecord暂停,让mPausingActivity指向它。
    ActivityStack#resumeTopActivityInnerLocked方法代码段

    final ActivityRecord next = topRunningActivityLocked(null);
    ...
    if (mResumedActivity != null) {
        pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);
    }
    
    • 7:ActivityStack#startPausingLocked方法Pause上一个Resume的Activity,即mResumedActivity,设置mResumedActivity是null。

    ProcessRecord的ApplicationThread,schedulePauseActivity方法,向App主线程发送一个PAUSE_ACTIVITY消息。完成上一个Activity的onPause生命周期方法。
    同时发送一个延迟500毫秒的PAUSE_TIMEOUT_MSG消息到system_server进程的ActivityManager线程消息队列。
    ActivityStack#startPausingLocked方法代码段

    ActivityRecord prev = mResumedActivity;
    ...
    mResumedActivity = null;
    mPausingActivity = prev;
    ...
    if (prev.app != null && prev.app.thread != null) {    
        try {
            prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
                            userLeaving, prev.configChangeFlags, dontWait);
        } catch (Exception e) {
            mPausingActivity = null;
            mLastPausedActivity = null;
            mLastNoHistoryActivity = null;
        }
    } 
    
    if (mPausingActivity != null) {
        if (dontWait) {
            completePauseLocked(false);
            return false;
        } else {
            Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
            msg.obj = prev;
            prev.pauseTime = SystemClock.uptimeMillis();
            mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
            return true;
        }
    }
    
    • 8:startPausingLocked方法后,结果pausing是true。ActivityStack#resumeTopActivityInnerLocked方法返回,一步步按原路返回,系统服务进程AMS的Binder处理线程结束,回到App进程启动Activity组件的Instrumentation#execStartActivity位置返回结果。
    if (pausing) {
        if (next.app != null && next.app.thread != null) {
            mService.updateLruProcessLocked(next.app, true, null);
         }
        if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
        return true;
    }
    

    App主线程从休眠中唤醒,checkStartActivityResult(result, intent)处理result,继续从主消息队列中取消息,下一个应该是在服务进程ApplicationThread#schedulePauseActivity处发送的PAUSE_ACTIVITY消息。

    • 9:在App主线程和system_server的ActivityManager线程均有待处理的消息,并行。

    两者进入AMS执行的代码都是activityPausedLocked方法
    在App进程中,处理前一个Activity生命周期onPause方法。token是App与AMS中表示Activity的唯一标识。
    ActivityThread#handlePauseActivity方法

    handlePauseActivity(IBinder token, boolean finished,
                boolean userLeaving, int configChanges, boolean dontReport){
        ActivityClientRecord r = mActivities.get(token);
        ...
        performPauseActivity(token, finished, r.isPreHoneycomb());
        ...
        ActivityManagerNative.getDefault().activityPaused(token);
    }
    

    发起system_server进程AMS调用,触发AMS#activityPaused方法,告诉AMS,token标识的Activity已执行生命周期方法onPause。
    AMS#activityPaused方法。

    @Override
    public final void activityPaused(IBinder token) {
        ...
        synchronized(this) {
            ActivityStack stack = ActivityRecord.getStackLocked(token);
            if (stack != null) {
                stack.activityPausedLocked(token, false);
            }
        }
        ...
    }
    

    system_server进程启动一个新Binder线程处理。进入ActivityStack#activityPausedLocked方法。同时,ActivityManager线程消息队列中get待处理的消息,也会执行ActivityStack#activityPausedLocked方法,不过它有一个延迟,所以一般情况下新Binder线程快一些。两个线程执行activityPausedLocked代码块需synchronized同步。

    public void handleMessage(Message msg) {
        synchronized (mService) {
            ...
            activityPausedLocked(r.appToken, true);
        }
    }
    
    • 10:ActivityStack#activityPausedLocked,触发completePauseLocked。
    final void activityPausedLocked(IBinder token, boolean timeout) {
        final ActivityRecord r = isInStackLocked(token);
        if (r != null) {
            mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
            if (mPausingActivity == r) {
                completePauseLocked(true);
            } else {
                ....
            }
        }
    }
    

    如果一个线程已经执行过此处代码,则将mPausingActivity设置为空,则另一个线程判断后就不会继续执行。

    从completePauseLocked中到ActivityStackSupervisor#resumeTopActivitiesLocked,已完成前Activity的暂停,接下来要Resume新的ActivityRecord,此时mResumedActivity已设置为空,因此pause状态是false,继续走流程。
    程序调试截图如下:


    pause为false.png
    • 11:在ActivityStack#resumeTopActivityInnerLocked中,next代表要启动的ActivityRecord,此时ActivityRecord内部ProcessRecord还未设置,next.app是空,所以会进入方法ActivityStackSupervisor#startSpecificActivityLocked。
    ActivityStack#resumeTopActivityInnerLocked代码片段
    if (next.app != null && next.app.thread != null) {
        .....
    }else{
        mStackSupervisor.startSpecificActivityLocked(next, true, true);
    }
    
    • 12:获取ProcessRecord,判断是否需创建进程。根据ActivityRecord包名以及application的uid获取ProcessRecord,它代表此ActivityRecord的进程。

    ActivityStackSupervisor#startSpecificActivityLocked方法

    void startSpecificActivityLocked(ActivityRecord r,
                boolean andResume, boolean checkConfig) {
        ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                    r.info.applicationInfo.uid, true);
        .....
        //如果ProcessRecord不为空,说明进程已经存在,直接realStartActivityLocked后退出。
        if (app != null && app.thread != null) {
            try {
                .....
                realStartActivityLocked(r, app, andResume, checkConfig);
                return;
            } catch (RemoteException e) {
            }
        }
        //ProcessRecord不存在,创建进程
        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                    "activity", r.intent.getComponent(), false, false, true);
    }
    
    • 13:ActivityStackSupervisor#realStartActivityLocked,将ProcessRecord赋值到ActivityRecord内部,scheduleLaunchActivity调用App进程,App进程启动一个Binder线程,向App主线程发送一个LAUNCH_ACTIVITY消息。

    LAUNCH_ACTIVITY消息将开启Activity对象创建及生命周期。

    final boolean realStartActivityLocked(ActivityRecord r,
                ProcessRecord app, boolean andResume, boolean checkConfig)
                throws RemoteException {
        mWindowManager.setAppVisibility(r.appToken, true);
        ...
        r.app = app;
        ...
        app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                        System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
                        new Configuration(stack.mOverrideConfig), r.compat, r.launchedFromPackage,
                        task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
                        newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);
        ...
    }
    

    system_server的ActivityManager线程执行到这里,PAUSE_TIMEOUT_MSG消息处理完毕。
    如果AMS是Binder线程先执行,也是同样的逻辑,处理完返回到以下代码处。

    ActivityManagerNative.getDefault().activityPaused(token)
    

    PAUSE_ACTIVITY消息就处理完啦。

    当App主线程接收到LAUNCH_ACTIVITY消息,开始Activity对象创建,生命周期。AMS进程传递给App的参数包含token,最终存储在Activity内部,其他参数如ActivityInfo等。


    ^^

    相关文章

      网友评论

        本文标题:界面显示_Activity启动流程

        本文链接:https://www.haomeiwen.com/subject/bhpdzxtx.html