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