OpenHarmony开发者论坛
标题:
OpenHarmony_Ability启动流程分析
[打印本页]
作者:
Laval社区小助手
时间:
2023-12-26 15:19
标题:
OpenHarmony_Ability启动流程分析
[md]**详情:[OpenHarmony_Ability启动流程分析](
https://laval.csdn.net/64801ef39787b754b2643f00.html
)**
startAbility函数用于启动一个Ability,是AMS中提供的接口,并且在应用中可以通过Ability API调用。本文通过分析startAbility函数的执行过程,来介绍Ability启动时的主要流程。
## 总览
> 本文只涉及FA模型中的Page Ability与Stage模型中的Ability,不包含Particle Ability(FA)或Extension Ability(Stage)。
>
> 有关Ability的基本知识与对应的模型请参考:[Ability框架概述](
https://gitee.com/openharmony/do ... .md?login=from_csdn
)
整体流程图: ![overview](
https://devpress.csdnimg.cn/40673b63265e4bf5b65d48d639523611.png
)
这里我们将启动流程分为三个阶段:创建任务、启动应用(可选)、启动Ability,接下来深入细节看每个阶段的具体流程。
## 创建任务
整个启动流程最初就是创建任务(Mission)并将其加入到合适的任务链(MissionList)中,期间还会创建其他的对象比如AbilityRequest、AbilityRecord等。
### 1. 创建AbilityRequest
AbilityRequest用于描述一个启动请求,在AMS中创建。其中包含了待启动的Ability的信息、app的信息(通过BMS获取),请求的Want,调用者的信息等,以供后续流程获取这些信息。
### 2. 决策任务链
接下来需要决定目标任务放在哪个任务链中,任务链的选择是在MissionListManager中进行的,遵循着以下规则:
1. 目标是launcher,使用launcherList
2. 调用方是sa,new MissionList
3. 调用方是launcher
* 如果目标是singleton,判断是否之前启动过该ability并找到对应的Mission和MissionList
* 不是则新建MissionList
4. 如果调用方的MissionList不是defaultStandardList 与defaultSingleList,则使用调用方的MissionList
5. 如果是,则新建MissionList,将调用方加入到该list中
#### 2.1 MissionListManager
AMS维护了MissionListManager,每个user对应一个MissionListManager。MissionListManager用于管理所有的Mission(任务,一个任务对应一个AbilityRecord)与任务链MissionList,并提供了一些对ability的操作(最小化、结束、启动等),其内部维护了一个MissionList的列表。
#### 2.2 MissionList
管理着用户启动的一个任务链,记录了任务之间的拉起关系,是启动的任务(Mission)的集合,使用链表进行管理。为了方便管理,有以下几个特殊的任务链:
1. launcherList:launcher单独占据一个MissionList
2. defaultSingleList:任务链被破坏后,singleton的任务被移动到该MissionList
3. defaultStandardList :任务链被破坏后,standard的任务被移动到该MissionList
#### 2.3 Mission
Mission代表了用户启动的一个任务,一个Mission对应一个Ability记录。普通Ability每启动一次都会创建一个Mission,singleton类型的Ability则会复用。Mission仅用作记录信息。
![](file:///C:/Users/kuangansheng/Desktop/%E8%AF%BE%E7%A8%8B%E6%A1%88%E4%BE%8BFAQ/%E8%AF%BE%E7%A8%8B%E6%A1%88%E4%BE%8BFAQ/%E5%85%AC%E5%BC%80%E8%AF%BE%E7%A8%8B/OpenHarmony_Ability%E5%90%AF%E5%8A%A8%E6%B5%81%E7%A8%8B%E5%88%86%E6%9E%90/img/relation.png?lastModify=1686118089)
![](
https://devpress.csdnimg.cn/4f439180813f468fac966a8060801071.png
)
### 3. 创建Misson与AbilityRecord
决定任务链后,需要创建Mission与其对应的AbilityRecord:
1. singleton模式的Ability尝试复用Mission
2. 根据AbilityRequest创建AbilityRecord
3. 创建InnerMissionInfo与MissionInfo
4. 如果Mission为空,通过InnerMissionInfo的id、missionName与AbilityRecord生成Mission
5. AbilityRecord与Mission相互持有引用
6. 将InnerMissionInfo存入MissionInfoMgr
#### 3.1 任务类概览图
![](file:///C:/Users/kuangansheng/Desktop/%E8%AF%BE%E7%A8%8B%E6%A1%88%E4%BE%8BFAQ/%E8%AF%BE%E7%A8%8B%E6%A1%88%E4%BE%8BFAQ/%E5%85%AC%E5%BC%80%E8%AF%BE%E7%A8%8B/OpenHarmony_Ability%E5%90%AF%E5%8A%A8%E6%B5%81%E7%A8%8B%E5%88%86%E6%9E%90/img/mission.png?lastModify=1686118089)
![](
https://devpress.csdnimg.cn/82adb6ae39d24dd0a0fdbbdf32d5ee85.png
)
#### 3.2 AbilityRequest与AbilityRecord
AbilityRequest表示一个请求,仅用作信息存储。AbilityRecord则表示一个Ability记录,AbilityRecord中的Ability信息与App信息均来自于AbilityRequest。AbilityRecord还存有want、preAbilityRecord*、nextAbilityRecord*、backAbilityRecord\_、ability的运行信息等,以及一些对ability操作的api。后续AMS内通过AbilityRecord来获取Ability与其对应App的信息,并且对Ability的操作也是通过AbilityRecord来触发的。
#### 3.3 InnerMissionInfo与MissionInfo
MissionInfo是元能力对外提供的用于描述任务信息的实体,其中包含任务的运行状态、运行时间、want引用、ability图标与名字等信息,对上提供任务api的数据就是来自于MissionInfo。InnerMissionInfo则是ams内部使用的实体,包含了MissionInfo的引用、bundleName,uid等信息。两者均为纯数据对象。
#### 3.4 MissionInfoMgr
MissionInfoMgr管理着InnerMissionInfo,AMS与外部组件均直接或间接通过MissionInfoMgr来获取InnerMissionInfo中的MissionInfo,如当前任务的状态、快照等。WMS会为MissionInfoMgr注册快照处理器,用来生成任务快照。
### 4. 加入任务链
第一阶段的最后一步,是将创建的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:
oadAbility尝试装载Ability,其内部通过AppRunningManager判断应用是否已经启动,即是否是第一次启动。如果是会优先启动应用进程并创建Application,待应用启动完毕后再装载目标Ability。
### 1. 创建AppRunningRecord
AppRunningManager内部维护了所有应用的运行记录,即AppRunningRecord。AppRunningRecord记录了应用的信息、应用的运行状态(CREATE、READY、FOREGROUND、BACKGROUND、SUSPENDED、TERMINATED、END)、进程信息等,内部持有了模块运行信息列表。
应用第一次启动时,会先创建AppRunningRecord:
1. 从BMS获取app、hap、ability的信息
2. 决定进程名,规则为module.json中的process或bundleName
3. 将以上信息传递给AppRunningManager来创建
4. 为AppRunningRecord添加模块运行信息
### 2. 启动App进程
接下来根据进程名启动App进程:
1. 如果在startAbility时,want内将coldStart设置为true,那么后续会执行冷启动流程
2. 基于appspawn进程fork app进程
3. 冷启动
* 使用execv执行子程序替换当前进程的正文、数据、堆和栈段
* 子程序为appspawn\_start\_app.cpp中的main函数
* new一个AppSpawnServer,并调用AppColdStart函数
* AppColdStart内会通过dlopen装载ace与nweb的so库
* 与热启动一样
4. 热启动
* 配置应用沙箱
* 设置进程名
* 设置uid与gid
* 通知父进程启动结果
* 启动MainThread
### 3. 启动MainThread
接下来会调用AppExecFwk::MainThread::Start()函数,我们来看一看该函数内做了什么操作:
1. 创建主EventRunner
2. 创建MainThread实例
3. 初始化与Main EventRunner对应的Main Handler
4. 初始化一个名为TaskRunner的EventRunner与其对应的EventHandler,创建了名为TaskRunner的线程,主要用于Ability执行非UI任务
5. 后续的所有流程包括启动应用、启动Ability均是在Start函数中触发的,在Start函数的最后是启动主EventRunner,这里将其提前以保持连贯性。EventRunner内部维护了一个消息队列,在启动后不断地从队列中取出事件交给对应的EventHandler处理。
### 4. 创建应用上下文
接下来程序执行到MainThread::Attach函数,最终会调用到MainThread的HandleLaunchApplication函数:
1. 装载/system/lib/libace.z.so
2. 创建ApplicationImpl对象
3. 创建AbilityRecordMgr对象,用于管理AbilityLocalRecord
4. 创建ContextDeal,并为其设置进程、应用、代码路径等信息,后续会将其设置到OHOSApplication对象中
5. 创建OHOSApplication对象
6. 初始化ResourceManager,用于应用加载资源
7. 创建AbilityRuntime::ContextImpl,并将其设置到OHOSApplication对象中,作为AbilityStage Context的parent
8. Stage模式下会创建JsRuntime并设置给OHOSApplication,用于解释执行abc文件,其内部通过方舟引擎ArkNativeEngine实现该功能
#### 4.1 Context概览图
![](file:///C:/Users/kuangansheng/Desktop/%E8%AF%BE%E7%A8%8B%E6%A1%88%E4%BE%8BFAQ/%E8%AF%BE%E7%A8%8B%E6%A1%88%E4%BE%8BFAQ/%E5%85%AC%E5%BC%80%E8%AF%BE%E7%A8%8B/OpenHarmony_Ability%E5%90%AF%E5%8A%A8%E6%B5%81%E7%A8%8B%E5%88%86%E6%9E%90/img/context.png?lastModify=1686118089)
![](
https://devpress.csdnimg.cn/8780a424fbda4428a9906086a3b788d4.png
)
#### 4.2 ContextDeal与OHOSApplication
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
TaskDispatcher与TaskExecutor一起协同工作,TaskDispatcher负责任务的分发,TaskExecutor则负责任务的执行。TaskDispatcher按业务目标分为很多类型,如UITaskDispatcher、主线程TaskDispatcher、ParallelTaskDispatcher、GlobalTaskDispatcher等。
#### 4.3 ContextDeal与ContextImpl
ContextDeal是AppExecFwk::Context的实现,而ContextImpl是AbilityRuntime::Context的实现。两者有什么区别呢?
##### AppExecFwk::Context
* 程序执行框架中的上下文
* 包含了程序执行时需要的能力,如创建与获取TaskDispatcher、获取BMS、获取进程信息、对Mission的操作等
* 提供了大部分AbilityRuntime::Context的能力
##### AbilityRuntime::Context
* Ability运行时的上下文
* 仅提供Ability运行中的信息获取,如获取应用信息、代码与缓存目录、资源管理器等。
#### 4.4 OHOSApplication与ApplicationImpl
ApplicationImpl持有OHOSApplication,内部记录了Application的状态,以及一系列Perform函数,如PerformForeground、PerformBackground等,Perform函数内则会调用OHOSApplication中的生命周期函数。MainThread会在合适的时机调用Perform系列函数。
##### Application的状态
* APP\_STATE\_CREATE
* APP\_STATE\_READY
* APP\_STATE\_FOREGROUND
* APP\_STATE\_BACKGROUND
* APP\_STATE\_TERMINATED
### 5. 启动应用
在Attach的最后,会调用ApplicationImpl:
erformAppReady来启动应用,也就是调用应用的生命周期函数并设置应用状态为APP\_STATE\_READY:
1. 调用OHOSApplication的OnStart函数
2. 应用状态设置为APP\_STATE\_READY
3. 将AppRunningRecord中的应用状态也设置为APP\_STATE\_READY
4. 启动Pending状态的Abilities,即状态为ABILITY\_STATE\_CREATE的Ability
## 启动Ability
在startAbility函数执行过程中,会根据Want对象中的BundleName与AbilityName创建AbilityRequest对象,最终在AppMgrServiceInner中创建AppRunningRecord对象。在创建时会为其添加ModuleRunningRecord,并且为ModuleRunningRecord添加AbilityRunningRecord。AbilityRunningRecord则是根据AbilityRecord中的AbilityInfo生成。
**三者对应关系如下:**
![](file:///C:/Users/kuangansheng/Desktop/%E8%AF%BE%E7%A8%8B%E6%A1%88%E4%BE%8BFAQ/%E8%AF%BE%E7%A8%8B%E6%A1%88%E4%BE%8BFAQ/%E5%85%AC%E5%BC%80%E8%AF%BE%E7%A8%8B/OpenHarmony_Ability%E5%90%AF%E5%8A%A8%E6%B5%81%E7%A8%8B%E5%88%86%E6%9E%90/img/AppRunningRecord.png?lastModify=1686118089)
![](
https://devpress.csdnimg.cn/2b95634b14b44b3391a5cab22571da37.png
)
Application启动成功后,会根据AbilityRunningRecord启动Ability,即startAbility时指定的Ability
### 1. 创建AbilityLocalRecord
根据AbilityInfo与token生成AbilityLocalRecord,AbilityLocalRecord主要用于存储信息,如AbilityInfo、EventRunner、AbilityImpl、AbilityThread等。其被AbilityRecordMgr管理,可以通过其获取Ability相关信息。
### 2. 创建AbilityStage
接下来调用OHOSApplication::AddAbilityStage生成AbilityStage,该函数接受的参数是AbilityLocalRecord:
1. 首先创建stageContext,类型为AbilityRuntime::ContextImpl
2. 将stageContext的父context设置为OHOSApplication中的Application Context
3. 寻找hap包内的AbilityStage.abc(ark运行时)并使用JsRuntime加载这个文件
4. 如果hap内没有module.json(FA模型),会手动拼接AbilityStage.abc的路径为/assets/js/AbilityStage.abc,在加载该文件时会直接返回一个空的NativeReference对象
5. 创建AbilityStage,Stage下具体实现类为JsAbilityStage,并将AbilityStage.abc解析出来的对象赋值给jsAbilityStageObj\_
6. 在Stage模型下创建js侧可用的AbilityStageContext对象(参考sdk目录下的api\\application\\AbilityStageContext.d.ts),FA模型由于jsAbilityStageObj\_对象为空,不在此创建context
7. 调用JS侧的OnCreate函数
8. 将AbilityLocalRecord缓存至AbilityStage中
9. 以moduleName为键缓存AbilityStage
AbilityStage作为Module级别的运行时,在Module加载与销毁的时候,可以通知开发者在此执行自己的逻辑,即生命周期。AbilityStage中记录了Module中的所有AbilityLocalRecord,OHOSApplication则记录了应用中所有的AbilityStage。
### 3. 创建AbilityThread
接着由MainThread创建AbilityThread,AbilityThread持有AbilityImpl,用于创建并管理调度ability的生命周期,一个ability对应一个AbilityThread:
1. 创建AbilityThread对象并执行Attach函数
2. 根据模型决定abilityName
* FA:AceAbility
* Stage:JsAbility
3. 创建AbilityHandler,其继承自EventHandler,用于post调度Ability的任务。其会被设置到AbilityImpl与AbilityLocalRecord中
### 4. 创建Ability
1. 通过AbilityLoader::GetInstance().GetAbilityByName(abilityName)创建Ability对象
* AceAbility:通过REGISTER\_AA(AceAbility)注册abilityName
* REGISTER\_AA则调用AbilityLoader::GetInstance().RegisterAbility注册abilityName,并返回new出来的Ability对象,即AceAbility
* JsAbility:调用 Ability::Create函数,当前Runtime为JS类型则创建JsAbility
2. 创建Ability的AppExecFwk::ContextDeal与AbilityRuntime::AbilityContextImpl,AbilityContextImpl中的Ability相关的函数如startAbility借由AbilityManagerClient实现,其他api借助AbilityRuntime::ContextImpl实现。具体参考[4.1 Context概览图](
https://laval.csdn.net/64801ef39 ... %BE?login=from_csdn
)
### 5. 创建AbilityImpl
Ability创建完成后接着创建与其对应的AbilityImpl对象。AbilityImpl通过AbilityImplFactory创建,AbilityImpl持有Ability的引用,是Ability的包装类,会在合适的时机调用生命周期函数。不同模式实现类不同:
* FA:PageAbilityImpl
* Stage:NewAbilityImpl
### 6. Init Ability
接下来由AbilityImpl执行Ability初始化操作:
1. 执行持有的Ability的Init,AceAbility与JsAbility都会先调用父类Ability的Init:
* Ability
* 一些初始化工作,如lifecycle初始化、application、context等的赋值
* 如果不是stage模式会创建AbilityWindow,内部会创建WindowScene,用于与窗口的交互
* AceAbility无额外的Init逻辑
* JsAbility
* 通过JsRuntime解释执行ability文件,如MainAbility.abc
* 创建js侧可用的ability context对象(参考sdk目录下的api\\application\\AbilityContext.d.ts)
### 7. Forground Application
初始化Ability后执行attach AbilityThread,在此期间如果application的状态不是APP\_STATE\_FOREGROUND,则将application置入前台:
1. 改变ApplicationImpl的状态为APP\_STATE\_FOREGROUND并执行OHOSApplication::OnForeground()
2. 将待置入前台的ability置入前台
3. 将application加入最近应用列表
### 8. Forground Ability
在将待置入前台的ability置入前台的过程中,根据ability的token找到对应的ModuleRunningRecord,并调用其OnAbilityStateChanged函数:
* 该函数会设置AbilityRunningRecord的状态为ABILITY\_STATE\_FOREGROUND,并回调OnAbilityRequestDone。
* 在AppScheduler::OnAbilityRequestDone的回调中,则通过MissionListManager找到对应的AbilityRecord,执行其ForegroundAbility函数.
* 最终调用链会执行到AbilityThread中AbilityImpl的HandleAbilityTransaction函数内,这里只关注Foreground的流程
#### 8.1 Start
如果当前Ability的生命周期状态为AAFwk::ABILITY\_STATE\_INITIAL,优先执行start流程:
##### FA
1. 调用AbilityImpl::Start(const Want &want)
2. 调用内部持有的ability\_的OnStart函数
3. FA对应的是AceAbility,内部会先调用Ability::OnStart(want)
4. 根据应用的bundleName,决定window的类型
5. FA模型下会创建并初始化main window
6. 更新context中的displayID、density等信息,并回调JS中的onUpdateConfiguration
7. 更新resourceManager中的density、屏幕方向等信息
8. 更新SystemProperties中的device info、color mode等信息
9. 更新resourceManager中的locale信息
最后初始化AceContainer、创建FlutterAceView、执行js page的代码、调用js侧的onCreate
##### Stage
1. 调用AbilityImpl::Start(const Want &want)
2. 调用内部持有的ability\_的OnStart函数
3. Stage对应的是JSAbility,内部会先调用Ability::OnStart(want);
4. 同FA模型,区别是此时不会创建window
最后回调js中的onCreate
#### 8.2 Forground
##### FA
在FA模型中,执行的是Active流程:
1. 调用PageAbilityImpl::AbilityTransactionNew
2. 该函数根据目标状态与当前状态执行不同的函数,在当前情况下会调用AbilityImpl::Active函数
3. 调用内部持有的ability\_的OnActive函数
4. FA对应的是AceAbility,内部会优先调用Ability::OnActive,继而执行abilityWindow\_->OnPostAbilityActive(),最终会调用show来显示窗口
5. 接着调用AceContainer::OnActive,最终回调js的onActive
6. 将Ability状态设置为ABILITY\_STATE\_ACTIVE
##### Stage
1. 调用NewAbilityImpl::AbilityTransaction函数
2. 该函数根据目标状态与当前状态执行不同的函数,在当前情况下会调用AbilityImpl::Foreground函数
3. 调用内部持有的ability\_的OnForeground函数
4. Stage对应的是JSAbility,最终会调用到JsAbility:
oOnForeground
5. 如果WindowScene未被创建则创建WindowScene、初始化main window并回调js中的onWindowStageCreate
6. 调用main window的show函数,用于显示窗口
7. 回调js中的onForeground
8. 将Ability状态设置为ABILITY\_STATE\_FOREGROUND\_NEW
到此Ability从启动到前台的流程就介绍完了。
[/md]
欢迎光临 OpenHarmony开发者论坛 (https://forums.openharmony.cn/)
Powered by Discuz! X3.5