Android

界面显示_Activity启动流程

2018-02-27  本文已影响5人  gczxbb

前言

从一个简单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

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记录。

final int launchFlags = intent.getFlags();
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。

启动模式在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清除。

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方法。

最上面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);
}

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;
    }
}
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消息。

两者进入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);
    }
}
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
ActivityStack#resumeTopActivityInnerLocked代码片段
if (next.app != null && next.app.thread != null) {
    .....
}else{
    mStackSupervisor.startSpecificActivityLocked(next, true, true);
}

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

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等。


^^

上一篇下一篇

猜你喜欢

热点阅读