Start Activity process
如何使用Intent做Activity的跳转
Intnet intent = new Intent(MainActivity.this,TestActivity.class);
startActivity(intent);
流程
-
. startActivity的函数,这个函数被声明在了Context类中,然后我们的Activity类有重写版本,所以会执行Activity类下的版本
startActivity–》startActivityForResult --》mInstrumentation.execStartActivit
上面有三个函数,基本上都是简单的判断和一些代码的封装,在最后一个函数中,执行了mInstrumentation对象下的execStartActivity函数,这个函数会做一些脱离应用进程的操作,准备通过IBinder机制将请求发送到Ams中。
这个实现就是执行intent脱离我们的应用线程,然后发送IBinder消息(俗称IPC)到Ams中,到此处便结束了应用之旅,开始进入系统内部. -
Ams(ActivityManagerService),因为是对外调用的接口,所以为了不做过多的逻辑处理,紧接着转发给了startActivityAsUser函数校验一下发起者身份。我们可以看到其余的参数都是透传过来的,但是最后多出来了一个UserId
UserId:手机上的用户标示,类似于电脑多用户,通过 应用uid / 100000 计算得出,0为手机持有者,默认值为0
Uid:应用id,普通用户从 10000 Pid:进程idAMS startActivity(0) --》startActivityAsUser–》ActivityStarter startActivityMayWait --》startActivityLocked --》startActivity(1)–》startActivity(2)–》startActivityUnchecked --> resumeFocusedStackTopActivityLocked --》ActivityStack resumeTopActivityUncheckedLocked --> resumeTopActivityInnerLocked --> ActivityThread scheduleLaunchActivity -->handleLaunchActivity --> performLaunchActivity --> mInstrumentation.callActivityOnCreate --> activity.performCreate --》onCreate
startActivityMayWait做了两件重要的事情,一个是获取ResolveInfo,一个是获取ActivityInfo,就是目标Activity的基本信息。
startActivityLocked仅仅是记录时间,然后清空mLastStartActivityRecord数组的位置,为即将要启动的Activity腾位置
startActivity(1)函数就分析完了,写的很长,但是逻辑并不复杂,主要就是处理startActivityForResult的逻辑和校验权限,最后还创建了一个目标activity的ActivityRecord对象就完了。
startActivity(2)函数很简单,也只是通知Wms(WindowManagerService)阻塞一下Surface,然后就转发到了startActivityUnchecked函数中继续处理了。
startActivityUnchecked做的核心功能就是识别并且处理启动模式,以及关联的启动栈、任务栈,最后选择完合适的任务栈后就准备调用resumeFocusedStackTopActivityLocked继续开启Activity
resumeFocusedStackTopActivityLocked函数定义在ActivityStackSupervisor类中,从类名上可以看得出来这个是个管理者,不参与具体实现,所以函数也很短,只是做简单的校验就立马转发。紧接着就被转发到了ActivityStack下的resumeTopActivityUncheckedLocked中了
resumeTopActivityInnerLocked函数就是对目标页的很多状态判断,还有pause我们的启动者,然后通知AT(ActivityThread)准备启动.
scheduleLaunchActivity函数内创建了一个ActivityClientRecord对象,然后通过handler发送命令LAUNCH_ACTIVITY,
Activity 显示(WMS)
接上Activity onCreate -->Window setContentView -->generateLayout–>inflate
-
PhoneWindow.setContentView()里先执行了installDecor(),这个方法也是第一时间执行generateDecor(),其实就是new出来一个DecorView。DecorView是一个根布局,是一个FrameLayout。DecorView如果初始化完成,会是这样的结构。当然这只是其中的一种,事实上会根据主题,Title情况而有不同的结构。
-
generateLayout方法里,layoutResource会根据是否dialog情况,title情况,actionbar情况,去取不同的xml资源。inflate出来后DecorView会调用addView方法把它添加进自身里。
1.Activity里面setContentView,实际上是利用PhoneWindow类创建DecorView,然后inflater出xml布局,放进DecorView内。此时View层级结构已经准备好,但还没跑measure、layout和draw三件套,也没有被大佬WMS接管显示出来。
2.想被WMS接管,需要操作IPC那套流程,所以需要使用WindowManager进行操作,它会通过ViewRootImpl,使用IWindowSession和IWindow两个IPC接口(应用程序访问WMS使用IWindowSession,WMS访问应用程序使用IWindow),最终让WMS接管。
3.界面显示出来是,会经过一系列流程条用到ViewRootImpl.performTraversals方法,里面会从DecorView开始,递归的执行measure、layout和draw三件套方法,最终确定大小,绘制界面。
多用户多屏显示异常问题
-
问题: 多用户并显示多屏时,显示异常,某些activity只显示在default display上面。
- 情况一:在第二屏第二用户上长按某APP,选择app info,settings的activity会在display 0上显示出来。
- 情况二:APP里面调用其他activity,也会在默认显示屏上显示出来。
-
分析:原生android已经支持多用户显示多屏上,但支持还不够完善,比如这里的activity,以及相应的dialog,toast,均会显示在display 0上。
-
代码分析(情况一):
-
showAppDetailsAsUser --》startActivityAsUser–》executeRequest
-
startActivityAsUser中的/* resultTo= */ null,导致后续的executeRequest中的sourceRecord没有初始化,后续的startActivityUnchecked中的display被设置成了default display,也就是display 0
-
问题解决:
-
获取调用app的display的info,来设置当前启动activity的display info
在executeRequest中插入
+ int calling_displayID = INVALID_DISPLAY;
+ ActivityRecord callerRecord = null;
+ if(callerApp != null) {
+ callerRecord = callerApp.getConfigActivityRecord();
+ if(callerRecord != null) {
+ calling_displayID = callerRecord.getDisplayId();
+ }
+ }
+ if (calling_displayID != INVALID_DISPLAY && checkedOptions != null){
+ //call from APP property
+ if (calling_displayID != checkedOptions.getCallerDisplayId()) {
+ checkedOptions.setCallerDisplayId(calling_displayID);
+ }
+ } else if (sourceRecord == null) {
+ //call from APP internal
+ sourceRecord = callerRecord;
+ }
+
mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
request.voiceInteractor, startFlags, true /* doResume */, checkedOptions, inTask,