564
社区成员




startAbility函数用于启动一个Ability,是AMS中提供的接口,并且在应用中可以通过Ability API调用。本文通过分析startAbility函数的执行过程,来介绍Ability启动时的主要流程。
本文只涉及FA模型中的Page Ability与Stage模型中的Ability,不包含Particle Ability(FA)或Extension Ability(Stage)。
有关Ability的基本知识与对应的模型请参考:Ability框架概述
整体流程图:
这里我们将启动流程分为三个阶段:创建任务、启动应用(可选)、启动Ability,接下来深入细节看每个阶段的具体流程。
整个启动流程最初就是创建任务(Mission)并将其加入到合适的任务链(MissionList)中,期间还会创建其他的对象比如AbilityRequest、AbilityRecord等。
AbilityRequest用于描述一个启动请求,在AMS中创建。其中包含了待启动的Ability的信息、app的信息(通过BMS获取),请求的Want,调用者的信息等,以供后续流程获取这些信息。
接下来需要决定目标任务放在哪个任务链中,任务链的选择是在MissionListManager中进行的,遵循着以下规则:
AMS维护了MissionListManager,每个user对应一个MissionListManager。MissionListManager用于管理所有的Mission(任务,一个任务对应一个AbilityRecord)与任务链MissionList,并提供了一些对ability的操作(最小化、结束、启动等),其内部维护了一个MissionList的列表。
管理着用户启动的一个任务链,记录了任务之间的拉起关系,是启动的任务(Mission)的集合,使用链表进行管理。为了方便管理,有以下几个特殊的任务链:
Mission代表了用户启动的一个任务,一个Mission对应一个Ability记录。普通Ability每启动一次都会创建一个Mission,singleton类型的Ability则会复用。Mission仅用作记录信息。
决定任务链后,需要创建Mission与其对应的AbilityRecord:
AbilityRequest表示一个请求,仅用作信息存储。AbilityRecord则表示一个Ability记录,AbilityRecord中的Ability信息与App信息均来自于AbilityRequest。AbilityRecord还存有want、preAbilityRecord_、nextAbilityRecord_、backAbilityRecord_、ability的运行信息等,以及一些对ability操作的api。后续AMS内通过AbilityRecord来获取Ability与其对应App的信息,并且对Ability的操作也是通过AbilityRecord来触发的。
MissionInfo是元能力对外提供的用于描述任务信息的实体,其中包含任务的运行状态、运行时间、want引用、ability图标与名字等信息,对上提供任务api的数据就是来自于MissionInfo。InnerMissionInfo则是ams内部使用的实体,包含了MissionInfo的引用、bundleName,uid等信息。两者均为纯数据对象。
MissionInfoMgr管理着InnerMissionInfo,AMS与外部组件均直接或间接通过MissionInfoMgr来获取InnerMissionInfo中的MissionInfo,如当前任务的状态、快照等。WMS会为MissionInfoMgr注册快照处理器,用来生成任务快照。
第一阶段的最后一步,是将创建的Mission加入到决策好的MissionList中,然后将MissionList添加至MissionListManager的顶部。
在将Mission加入到MissionList中时,如果该Mission是被复用的,已经加入到MissionList中了,并且原来的任务链与现在的任务链不是同一个,或者调用方是Launcher或者sa,那么原任务链就会被破坏。原任务链内的standard任务被移动到该defaultStandardList ,singleton任务被移动到该defaultSingleList。
举个例子:
Ability A启动了singleton类型的Ability S,Ability B在后面某个时间点再一次启动了S,S原先的任务链是A的任务链,现在的任务链是B的任务链,两者不相同,A的任务链被破坏了。A的任务链中的任务会被移至default链中,S则被加入B的任务链顶部,B的任务链被移至MissionListManager顶部。
任务与任务链准备完成后,通过AppMgrServiceInner::LoadAbility尝试装载Ability,其内部通过AppRunningManager判断应用是否已经启动,即是否是第一次启动。如果是会优先启动应用进程并创建Application,待应用启动完毕后再装载目标Ability。
AppRunningManager内部维护了所有应用的运行记录,即AppRunningRecord。AppRunningRecord记录了应用的信息、应用的运行状态(CREATE、READY、FOREGROUND、BACKGROUND、SUSPENDED、TERMINATED、END)、进程信息等,内部持有了模块运行信息列表。
应用第一次启动时,会先创建AppRunningRecord:
接下来根据进程名启动App进程:
如果在startAbility时,want内将coldStart设置为true,那么后续会执行冷启动流程
基于appspawn进程fork app进程
冷启动
热启动
接下来会调用AppExecFwk::MainThread::Start()函数,我们来看一看该函数内做了什么操作:
接下来程序执行到MainThread::Attach函数,最终会调用到MainThread的HandleLaunchApplication函数:
ContextDeal与OHOSApplication均继承自AppExecFwk::Context,区别就是OHOSApplication的直接父类是AppExecFwk::ApplicationContext。OHOSApplication中多了一些函数,如对AbilityStage的操作,以及Application的生命周期函数,如OnForeground、OnBackground。其还实现了AbilityLifecycleCallbacks,并提供了RegisterAbilityLifecycleCallbacks函数,用于在Ability生命周期变化时触发注册进来的回调函数。
ContextDeal与OHOSApplication相互持有,ContextDeal借助OHOSApplication实现CreateTaskDispatcher()系列的函数,OHOSApplication借助ContextDeal实现其他上下文函数,诸如GetProcessInfo、GetApplicationInfo、GetResourceManager等。
TaskDispatcher与TaskExecutor一起协同工作,TaskDispatcher负责任务的分发,TaskExecutor则负责任务的执行。TaskDispatcher按业务目标分为很多类型,如UITaskDispatcher、主线程TaskDispatcher、ParallelTaskDispatcher、GlobalTaskDispatcher等。
ContextDeal是AppExecFwk::Context的实现,而ContextImpl是AbilityRuntime::Context的实现。两者有什么区别呢?
ApplicationImpl持有OHOSApplication,内部记录了Application的状态,以及一系列Perform函数,如PerformForeground、PerformBackground等,Perform函数内则会调用OHOSApplication中的生命周期函数。MainThread会在合适的时机调用Perform系列函数。
在Attach的最后,会调用ApplicationImpl::PerformAppReady来启动应用,也就是调用应用的生命周期函数并设置应用状态为APP_STATE_READY:
在startAbility函数执行过程中,会根据Want对象中的BundleName与AbilityName创建AbilityRequest对象,最终在AppMgrServiceInner中创建AppRunningRecord对象。在创建时会为其添加ModuleRunningRecord,并且为ModuleRunningRecord添加AbilityRunningRecord。AbilityRunningRecord则是根据AbilityRecord中的AbilityInfo生成。
三者对应关系如下:
Application启动成功后,会根据AbilityRunningRecord启动Ability,即startAbility时指定的Ability
根据AbilityInfo与token生成AbilityLocalRecord,AbilityLocalRecord主要用于存储信息,如AbilityInfo、EventRunner、AbilityImpl、AbilityThread等。其被AbilityRecordMgr管理,可以通过其获取Ability相关信息。
接下来调用OHOSApplication::AddAbilityStage生成AbilityStage,该函数接受的参数是AbilityLocalRecord:
AbilityStage作为Module级别的运行时,在Module加载与销毁的时候,可以通知开发者在此执行自己的逻辑,即生命周期。AbilityStage中记录了Module中的所有AbilityLocalRecord,OHOSApplication则记录了应用中所有的AbilityStage。
接着由MainThread创建AbilityThread,AbilityThread持有AbilityImpl,用于创建并管理调度ability的生命周期,一个ability对应一个AbilityThread:
Ability创建完成后接着创建与其对应的AbilityImpl对象。AbilityImpl通过AbilityImplFactory创建,AbilityImpl持有Ability的引用,是Ability的包装类,会在合适的时机调用生命周期函数。不同模式实现类不同:
接下来由AbilityImpl执行Ability初始化操作:
初始化Ability后执行attach AbilityThread,在此期间如果application的状态不是APP_STATE_FOREGROUND,则将application置入前台:
在将待置入前台的ability置入前台的过程中,根据ability的token找到对应的ModuleRunningRecord,并调用其OnAbilityStateChanged函数:
该函数会设置AbilityRunningRecord的状态为ABILITY_STATE_FOREGROUND,并回调OnAbilityRequestDone。
在AppScheduler::OnAbilityRequestDone的回调中,则通过MissionListManager找到对应的AbilityRecord,执行其ForegroundAbility函数.
最终调用链会执行到AbilityThread中AbilityImpl的HandleAbilityTransaction函数内,这里只关注Foreground的流程
如果当前Ability的生命周期状态为AAFwk::ABILITY_STATE_INITIAL,优先执行start流程:
调用AbilityImpl::Start(const Want &want)
调用内部持有的ability_的OnStart函数
FA对应的是AceAbility,内部会先调用Ability::OnStart(want)
根据应用的bundleName,决定window的类型
FA模型下会创建并初始化main window
更新context中的displayID、density等信息,并回调JS中的onUpdateConfiguration
更新resourceManager中的density、屏幕方向等信息
更新SystemProperties中的device info、color mode等信息
更新resourceManager中的locale信息
最后初始化AceContainer、创建FlutterAceView、执行js page的代码、调用js侧的onCreate
调用AbilityImpl::Start(const Want &want)
调用内部持有的ability_的OnStart函数
Stage对应的是JSAbility,内部会先调用Ability::OnStart(want);
同FA模型,区别是此时不会创建window
最后回调js中的onCreate
在FA模型中,执行的是Active流程:
到此Ability从启动到前台的流程就介绍完了。