您当前的位置: 首页 > 

润和HiHope社区

暂无认证

  • 6浏览

    0关注

    105博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Ability的生命周期和JS中的回调函数

润和HiHope社区 发布时间:2020-12-17 11:03:41 ,浏览量:6

本文作者:江苏润和软件股份有限公司 郎建中

一、总体介绍 在分布式调度里面,我们介绍了一个例子:从分布式调度拉起远程FA的过程。在这个介绍中,我们最后讲到远端(轻量设备侧)软总线收到消息后,dmslite(分布式调度)通过AMS(Ability Manager Service)的方法StartAbility来启动本地的一个应用。整个系统的架构图如下: 在这里插入图片描述 AMS通过AppSpawn服务拉起了AbilityMain进程,AbilityMain进程就是App应用的native实现,其中包含了Ability生命周期实现、JS应用框架(Jerry)的初始化、App中的JS代码的执行、UI控件的绘制等工作。 AMS拉起FA的参考时序图如下: 在这里插入图片描述 上面的流程大体上分以下几个过程: 1、从dmslite收到软总线消息后,通过samgr调用ams的StartAbility(步骤1~3)。 2、AMS内部启动了一个StartAbilityTask任务去调用AppSpawn(步骤4~15)。 3、AppSpawn孵化出AbilityMain进程(步骤16~17)。 4、AbilityMain进程从main函数开始执行,在主线程函数ThreadMain中,发消息ATTACH_BUNDLE给AMS。 5、AMS执行attach bundle的过程,一直到调用PageAbilityRecord::ActiveAbilty()函数开始Ability的生命周期过程。 从PageAbilityRecord::ActiveAbility()之后的流程将开启Ability的生命周期,下面主要介绍这个过程中生命周期中Ability状态的变化以及在这个过程中如何回调到App的JS代码中Ability的回调函数。 约束:本文涉及的场景都是在鸿蒙轻量设备侧。 二、代码目录 本文涉及的代码: foundation/appexecfwk:ams服务和AbilityMain主程序。 foundation/ace:JS应用开发框架。 三、代码分析 3.1 Ability启动时的生命周期和JS中的回调函数 在这里插入图片描述

我们从运行在foundation进程中的AMS的PageAbilityRecord::ActiveAbility()函数开始: 在这里插入图片描述 大家注意上面代码中参数state是 STATE_ACTIVE。 –> AppRecord::AbilityTransaction() 在这里插入图片描述 –> AbilityThreadClient::AbilityTransaction() 在这里插入图片描述 上面代码中,state被压入Ipc的参数中,最后调用Transact()发送IPC消息到AbilityMain进程,消息为SCHEDULER_ABILITY_LIFECYCLE。这个消息将在AbilityMain进程中的AbilityScheduler::AmsCallback()被处理,代码如下:

–> AbilityScheduler::AmsCallback() 在这里插入图片描述 –> AbilityScheduler::PerformTransactAbilityState() 在这里插入图片描述 上面代码中的scheduler_就是AbilityThread实例。 –> AbilityThread::PerformTransactAbilityState() 在这里插入图片描述 AbilityThread::PerformTransactAbilityState()函数控制Ability的状态变化的主入口。接收从AMS发过来的消息做状态变化,消息中目标的状态是STATE_ACTIVE,这个函数大致分3个步骤完成。 ①AbilityThread::PerformTransactAbilityState()步骤一:初始化AceAbility 函数在第一次被调用时,因为abilities_中没有任何东西,因此find函数肯定找不到对应token的ability,因此代码会走进红框中。然后判断当前的ability是JS App对应的还是由一个Native的Ability生成的,这里因为我们是FA,因此是JS App对应的,所以必须采用AceAbility实例来启动,因为只有AceAbility支持JS的运行环境(JerryScript)。 在AceAbility被构造后,调用了AceAbility::Init()函数,由于在AceAbility中没有定义这个函数,所以直接调用到了基类的Init函数,我们看下代码: 在这里插入图片描述 基类中的Init()函数进行了一些初始化设置,将Ability当前的状态设置为STATE_INITIAL状态。 ②AbilityThread::PerformTransactAbilityState()步骤二:执行生命周期 回到AbilityThread::PerformTransactAbilityState()函数,下面执行了AbilityThread::HandleLifecycleTransaction()函数: 在这里插入图片描述 HandleLifecycleTransaction()函数就是执行Ability状态变迁的核心函数。这个函数首先根据当前状态来执行状态准备,然后根据目标状态执行状态切换。在上面AceAbility::Init()过程中,已经把当前状态设置为STATE_INITIAL,所以AceAbility::OnStart()动作会被首先执行,然后根据参数state的目标状态为STATE_ACTIVE,因此AceAbility::OnActive()也会被执行。 我们先看看AceAbility::OnStart()的过程: 在这里插入图片描述 在AceAbility::OnStart()函数中,首先获取JS APP的包名,包的路径,然后调用JSAbility::Launch()函数加载JS APP应用,我们看下JSAbility::Launch()函数实现: 在这里插入图片描述 首先是参数校验。然后构建了JSAbility的实现类JSAbilityImpl的对象。接着调用了JSAbilityImpl::InitEnvironment()函数进行JS运行环境的初始化,这个函数将把Jerry初始化起来,然后注册了很多全局类供JS使用,最后运行App中的JS代码来构建UI页面。这里不讨论Jerry相关的东西,会在单独的文档中详细介绍。 在InitEnvironment()完成后,UI页面已经构建完成,下面通过JSAbilityImpl::DeliverCreate()来回调到JS中的onCreate函数,我们来看看怎么实现的: 在这里插入图片描述 –> JSAbilityImpl::InvokeOnCreate() 在这里插入图片描述 jerryx_get_property_str()是Jerry的API,这个函数可以获取JS中的对象属性。abilityModel_是在Jerry中运行的JS Ability的对象,ABILITY_LIFECYCLE_CALLBACK_ON_CREATE定义为字符串”onCreate”,因此这个调用就是拿到JS中的Ability的属性onCreate方法的句柄。 CallJSFunctionAutoRelease()就是执行上述拿到的onCreate函数句柄,也就是执行JS中的onCreate方法。在这里插入图片描述 –> CallJSFunction 在这里插入图片描述 我们看到,最终是执行了Jerry的API jerry_call_function()来实现回调到JS中的。

我们再回到JSAbilityImpl::DeliverCreate()函数中,调用了Router::Replace()函数: 在这里插入图片描述 Replace前半部分是初始化状态机,这个状态机是JS页面中的Ability的状态机,这里不多说了,有兴趣同学自己看下。后面是调用了ReplaceSync()函数,原因是参数async是false。 –> Router::ReplaceSync() 在这里插入图片描述 在ReplaceSync()函数中,将状态先设置到INIT_STATE: 在这里插入图片描述 因为参数newState是INIT_STATE,最终会走到PageInitState::Handle()函数:在这里插入图片描述 上面代码中先回调到了JS中的onInit方法,然后再把状态切到READY: 在这里插入图片描述 在AceAbility::OnStart()的最后,调用了基类的Ability::OnStart()函数,设置了Ability当前的状态为STATE_INACTIVE: 在这里插入图片描述 这样ability的状态从STATE_INITIAL切到了STATE_INACTIVE。

最后我们来看看AbilityThread::HandleLifecycleTransaction()函数中执行AceAbility::OnActive()的过程: 在这里插入图片描述 调用基类的方法Ability::OnActive()就是设置状态为STATE_ACTIVE。我们来看看JSAbilityImpl::Show(): 在这里插入图片描述 –>Router::Show() 在这里插入图片描述 ChangeState最终走到PageShowState::Handle()函数: 在这里插入图片描述 至此,Ability的状态从STATE_INITIAL --> STATE_INACTIVE --> STATE_ACTIVE。 JS 页面的Ability状态从UNDEFINED_STATE --> INIT_STATE --> READY_STATE --> BACKGROUND_STATE --> SHOW_STATE。 ③AbilityThread::PerformTransactAbilityState()步骤三:通知AMS状态切换完成 在这里插入图片描述 –> AbilityMsClient::SchedulerLifecycleDone() 在这里插入图片描述 在AbilityMsClient::SchedulerLifecycleDone()函数中,调用IClientProxy::Invoke()通过IPC机制发消息给AMS服务,消息为ABILITY_TRANSACTION_DONE,其中还有的state为STATE_ACTIVE。这个消息将被AMS服务中的AbilityMgrFeature::Invoke()函数所处理。下一节会分析这个处理过程。

3.2 原先在顶层的FA状态的切换 前面一节说明了FA被拉起过程中,这个被拉起FA的状态的变化以及JS中的回调函数何时被执行的。那么在这个FA拉起前,原先在顶层的那个FA的状态怎么变化的呢? 3.2.1 从STATE_ACTIVE 到 STATE_INACTIVE 在拉起FA过程的时序图中,AMS通过发起一个AbilityStartTask任务来启动AbilityMain进程。我们看下这个任务的函数: 在这里插入图片描述 上面的代码中的注释很详细,在拉起新的FA前,先查找当前的顶层Ability,然后将它的状态设置成STATE_INACTIVE,这个过程与上面介绍的类似,这里不再详细跟踪代码解释。

3.2.2 从 STATE_INACTIVE 到 STATE_BACKGROUND 在3.1节的最后,当FA的状态已经切到STATE_ACTIVE后,AbilityMain会向AMS服务发送ABILITY_TRANSACTION_DONE消息并携带STATE_ACTIVE。这个消息被AbilityMgrFeature::Invoke()所处理,我们跟踪下代码: 在这里插入图片描述 这里的invokeFuncList如下: 在这里插入图片描述 根据消息ABILITY_TRANSACTION_DONE,会调用AbilityMgrFeature::AbilityTransactionDoneInvoke(): 在这里插入图片描述 上述函数发送AMS_TRANSACTION_DONE消息,被AbilityMgrHandler::ServiceMsgProcess()函数处理:在这里插入图片描述 –> AbilityMgrHandler::AbilityTransaction()在这里插入图片描述

–> AbilityWorker::AbilityTransaction(),这里我们的状态是STATE_ACTIVE: 在这里插入图片描述 –> AbilityActivateTask::Execute() 在这里插入图片描述 在这个函数中,先更新当前的active ability的状态,然后找到Previous的Ability,也就是前一个顶层的FA ability,然后将前 Top Ability的状态设置到STATE_BACKGROUND,这个过程中会调用到JS的回调函数onHide。这里不详细跟踪了。

3.3 Ability停止时的生命周期和JS中的回调函数 Ability的停止比较特殊,它不是由AMS主动触发的流程,而是在其他状态切换中触发的。我们先来看看AMS中执行Stop流程的起点PageAbilityRecord::StopAbility(): 在这里插入图片描述

函数中设置目标的状态为STATE_INITIAL,然后调用AppRecord::AbilityTransaction()函数发送消息到AbilityMain进程(这与上面介绍的ActiveAbility流程一样),我们简单跟踪一下: –> AppRecord::AbilityTransaction() 在这里插入图片描述 –> AbilityThreadClient::AbilityTransaction() 在这里插入图片描述 通过IPC调用Transact()发送 SCHEDULER_ABILITY_LIFECYCLE 到AbilityMain进程,由AbilityScheduler::AmsCallback()函数处理: –> AbilityScheduler::AmsCallback() 在这里插入图片描述 –> AbilityThread::PerformTransactAbilityState() 在这里插入图片描述 –> AbilityThread::HandleLifecycleTransaction() 在这里插入图片描述 上面的代码简单分析下: 1、根据当前的状态,当前的状态应该可能是STATE_ACTIVE或者STATE_BACKGROUND,而STATE_INITIAL和STATE_INACTIVE状态都是中间状态不会长时间存在。所以如果当前状态是STATE_ACTIVE,那么先调用OnInactive()将状态切到STATE_INACTIVE。 2、目标状态是STATE_INITIAL。如果在第一步中状态被切到了STATE_INACTIVE,那么调用OnBackground()继续把状态切到STATE_BACKGROUND,最终在执行OnStop()前,当前状态只可能是STATE_BACKGROUND。 前面章节已经介绍过OnInactive()和OnBackground()调用,最终会调用JS的回调函数onHide()。这里不详细跟踪代码了。我们来看看AceAbility::OnStop(): 在这里插入图片描述 先调用基类的OnStop()函数,把状态切成STATE_INITIAL,然后调用JSAbility::TransferToDestroy(): –> JSAbility::TransferToDestroy() 在这里插入图片描述 –> JSAbilityImpl::CleanUp() 在这里插入图片描述 在这个函数中将调用 InvokeOnDestroy()最终会调用到JS中的onDestroy回调函数。然后释放JS运行环境,包括前期注册的一些JS全局对象类,JerryScript运行时库等,这里不详细介绍了。 回到这个小节的开始,PageAbilityRecord::StopAbility()这个调用什么情况下会被调用呢? 通过搜索代码,找到两个地方: 1、AbilityActivateTask::Execute()中: 在这里插入图片描述 AbilityActivateTask是AMS发起激活一个Ability的任务,最终会发消息给AbilityMain,这个前面有介绍。那么什么时候会发起这个任务呢?我猜有两种情况: a、主动拉起一个新的FA,就像前面介绍的分布式调度拉起FA的过程,在AbilityMain进程拉起后,通过发送ATTCH_BUNDLE给AMS后,由AMS发起AbilityActivateTask任务。这个过程我们在上面已经详细介绍过了。 b、有两个FA,一个在BACKGROUND,一个在TOP。此时需要将BACKGROUND的FA重新激活,AMS会主动发起AbilityActivateTask。在这种情况下,我们看上面的代码逻辑,activeAbility就是原来处于BACKGROUND状态,需要激活的FA,prevAbility为空,nextAbility就是本来在TOP的FA,现在需要执行Stop操作了。也就是当激活前一个FA的时候,当前的FA需要被Stop掉。 2、AbilityInactivateTask::Execute()中: 在这里插入图片描述 AbilityInactivateTask是AMS发起的Inactive某一个FA的任务。这里inactiveAbility是需要INACTIVE的FA,nextAbility是以inactiveAbility为起点的下一个FA(在Ability栈中高于当前的,也就是比当前的FA时间上后拉起的),prevAbility是以inactiveAbility为起点的前一个FA(在Ability栈中低于当前的,也就是比当前的FA时间上先拉起的)。 上面代码逻辑: 1、假如nextAbility存在,说明nextAbility是在当前需要INACTIVE的ability之后拉起的,然后因为重新激活了当前Ability而被Stop掉的Ability(AbilityActivateTask中有描述),现在把当前Ability INACTIVE后,需要重新Start起来,所以执行nextAbility->StartAbility()操作。 2、如果nextAbility不存在,PrevAbility存在,说明当前Ability就是Top的,现在需要INACTIVE,需要把前面的PrevAbility重新激活(ActiveAbility)。 3、如果nextAbility和PrevAbility都不存在,那么就把当前Ability Stop掉。按照代码里面的描述,当所有的Ability都不存在时,把launcher启动起来。

总结: 1、AMS在拉起FA的过程中,会先把前一个的Top Ability的状态设置成STATE_INACTIVE。然后会拉起AbilityMain进程。 2、新拉起来的Ability会向AMS发送ATTCH_BUNDLE消息。 3、AMS在ATTCH_BUNDLE消息处理中向AbilityMain 首次发送消息SCHEDULER_ABILITY_LIFECYCLE,参数为STATE_ACTIVE。 4、AbilityMain在首次的SCHEDULER_ABILITY_LIFECYCLE消息处理中,分别调用了AceAbility::OnStart()和AceAbility::OnActive()。 a)在AceAbility::OnStart()的过程中,状态从STATE_INITIAL 切换到 STATE_INACTIVE,JS中的回调函数依次被调用 onCreate, onInit , onReady。 b)在AceAbility::OnActive()的过程中,状态从STATE_INACTIVE 切换到 STATE_ACTIVE ,JS中的回调函数onShow被调用。 5、拉起的FA状态切到STATE_ACTIVE后,发送ABILITY_TRANSACTION_DONE消息通知AMS状态切换完成,AMS将把前一个Top Ability的状态切到STATE_BACKGROUND,同时会回调到JS的函数onHide。 6、当前Top Ability有一个PrevAbility,需要激活PrevAbility的情况下,会把当前TopAbility Stop掉。 7、当前激活的Ability存在nextAbility的情况下,需要INACTIVE当前激活Ability时,会把nextAbility重新Start起来。 8、当前Top Ability有一个PrevAbility,需要INACTIVE当前TopAbility,那么会把PrevAbility重新激活(ACTIVE) 9、当前Ability如果不存在PrevAbility和nextAbility,需要INACTIVE当前Ability的情况下,会把当前Ability Stop掉。 10、Ability的Stop过程,会回调到JS中的onDestory回调函数。 11、有两个状态机: a)一个是Ability:状态有STATE_INITIAL,STATE_INACTIVE,STATE_ACTIVE,STATE_BACKGROUND。 b)一个是JS Page State:UNDEFINED_STATE,INIT_STATE, READY_STATE, SHOW_STATE, BACKGROUND_STATE, DESTROY_STATE。这个状态机是JS页面的状态机。

下图是Ability生命周期状态图: 在这里插入图片描述

关注
打赏
1663234134
查看更多评论
立即登录/注册

微信扫码登录

0.0365s