OpenHarmony应用启动流程分析——Application&Ability初始化

作者:汪语

一、引言

本文基于OpenAtom OpenHarmony(以下简称“OpenHarmony”) 4.0 Release版本的源码,对应用进程初始化后MainThread初始化及调用AttachApplication、LaunchApplication、LaunchAbility的过程做了分析和总结,该流程贯穿了应用程序的用户进程和系统服务进程。

二、启动框架与核心类简介

1. 启动框架须知

如下图所示,OpenHarmony应用冷启动过程大致分为四个阶段:应用进程创建&初始化、Application&Ability初始化、Ability/AbilityStage生命周期、加载绘制首页。

2. 应用启动流程的核心类须知

●AppMgrService是应用管理服务主线程类,实现了IPC调用IAppMgr的接口,并通过AMSEventHandler将进程内各类事件及任务发送到主线程。
●AppRunningManager记录了应用的信息、应用的运行状态、进程信息等,内部持有了模块运行信息列表,应用第一次启动时,会先创建。
●AppSpawn是app孵化器,通过监听本地socket,接收客户端的请求消息。创建Ability应用所在进程,为Ability应用设置相应的权限,并预加载一些通用的模块。
●AbilityLoader负责注册和加载开发者Ability模块。开发者开发的Ability先调用AbilityLoader的注册接口注册到框架中,接着Ability启动时会被实例化。
●AbilityManager负责AbilityKit和Ability管理服务进行IPC的通信。
●MainThread是应用进程的核心类。应用进程内各类事件及任务通过MainThread中mainHandler投递到主线程并调用MainThread中的方法执行。
●AbilityThread是应用线程的核心类,是操作各种Ability生命周期及方法的入口。

三、源码分析

1.主线程初始化,通过IPC机制,AMS调用AttachApplication,再回调AMS端

foundation\ability\ability_runtime\frameworks\native\appkit\app\main_thread.cpp


 void MainThread::Start() 
 {
     sptr<MainThread> thread = sptr<MainThread>(new (std::nothrow) MainThread());
     ......
     thread->Init(runner);
     thread->Attach();  }

void MainThread::Init()
{
    auto task = [weak]() {
        auto appThread = weak.promote();
        appThread->SetRunnerStarted(true);
    };
    if (!mainHandler_->PostTask(task)) {
        HILOG_ERROR("MainThread::Init PostTask task failed");
    }
    watchdog_->Init(mainHandler_);
    extensionConfigMgr_->Init();
}

void MainThread::Attach()
{
    if (!ConnectToAppMgr()) {
        return;
    }
    mainThreadState_ = MainThreadState::ATTACH;
}

bool MainThread::ConnectToAppMgr()
{
    auto object = OHOS::DelayedSingleton<SysMrgClient>::GetInstance()->GetSystemAbility(APP_MGR_SERVICE_ID);
    appMgr_ = iface_cast<IAppMgr>(object);
    appMgr_->AttachApplication(this);  
}

客户端发送 attach application 请求foundation\ability\ability_runtime\interfaces\inner_api\app_manager\src\appmgr\app_mgr_proxy.cpp


AppMgrProxy::AttachApplication(const sptr<IRemoteObject> &obj)
{
    sptr<IRemoteObject> remote = Remote();
    remote->SendRequest(static_cast<uint32_t>(IAppMgr::Message::APP_ATTACH_APPLICATION), ...);
}

服务端收到 attach application 请求foundation\ability\ability_runtime\interfaces\inner_api\app_manager\src\appmgr\app_mgr_stub.cpp

int32_t AppMgrStub::HandleAttachApplication(MessageParcel &data, MessageParcel &reply)
{
    sptr<IRemoteObject> client = data.ReadRemoteObject();
    AttachApplication(client);  
}

foundation\ability\ability_runtime\services\appmgr\src\app_mgr_service.cpp

void AppMgrService::AttachApplication(const sptr<IRemoteObject> &app)
{
   pid_t pid = IPCSkeleton::GetCallingPid();
    AddAppDeathRecipient(pid);
    std::function<void()> attachApplicationFunc =
        std::bind(&AppMgrServiceInner::AttachApplication, appMgrServiceInner_, pid, iface_cast<IAppScheduler>(app));
    taskHandler_->SubmitTask(attachApplicationFunc, TASK_ATTACH_APPLICATION);
}

函数处理逻辑回到服务层foundation\ability\ability_runtime\services\appmgr\src/app_mgr_service_inner.cpp


void AppMgrServiceInner::AttachApplication(const pid_t pid, const sptr<IAppScheduler> &appScheduler)
{
    ......
    appRecord->SetApplicationClient(appScheduler);
    appRecord->RegisterAppDeathRecipient();
    if (appRecord->GetState() == ApplicationState::APP_STATE_CREATE) {
        LaunchApplication(appRecord);
    }
    eventInfo.pid = appRecord->GetPriorityObject()->GetPid();
    eventInfo.processName = appRecord->GetProcessName();
    AAFwk::EventReport::SendAppEvent(AAFwk::EventName::APP_ATTACH, HiSysEventType::BEHAVIOR, eventInfo);
}

void AppMgrServiceInner::LaunchApplication(const std::shared_ptr<AppRunningRecord> &appRecord)
{
    appRecord->LaunchApplication(*configuration_);
    appRecord->SetState(ApplicationState::APP_STATE_READY);
    appRecord->SetRestartResidentProcCount(restartResidentProcCount);
    ......
    appRecord->LaunchPendingAbilities();
    AAFwk::EventReport::SendAppEvent(AAFwk::EventName::APP_LAUNCH, HiSysEventType::BEHAVIOR, eventInfo);
}

2.应用初始化,通过AppRunningRecord调用LaunchApplication

应用第一次启动时,会先创建AppRunningRecordfoundation\ability\ability_runtime\services\appmgr\src\app_running_record.cpp

void AppRunningRecord::LaunchApplication(const Configuration &config)
{
    appLifeCycleDeal_->GetApplicationClient()
    ......
    launchData.SetProcessInfo(processInfo);
    launchData.SetRecordId(appRecordId_);
    launchData.SetUId(mainUid_);
    launchData.SetUserTestInfo(userTestRecord_);
    launchData.SetAppIndex(appIndex_);
    appLifeCycleDeal_->LaunchApplication(launchData, config);
}

foundation\ability\ability_runtime\services\appmgr\src\app_lifecycle_deal.cpp

void AppLifeCycleDeal::LaunchAbility(const std::shared_ptr<AbilityRunningRecord> &ability)
{
    appThread_->ScheduleLaunchApplication(launchData, config);
}

处理启动应用(加载依赖库、初始化资源管理器等)等逻辑foundation\ability\ability_runtime\frameworks\native\appkit\app\main_thread.cpp


void MainThread::ScheduleLaunchApplication(const AppLaunchData &data, const Configuration &config)
{
    appThread->HandleLaunchApplication(data, config);
}

void MainThread::HandleLaunchApplication(const AppLaunchData &data, const Configuration &config)
{
    if (!InitCreate(contextDeal, appInfo, processInfo)) {
        return;
    }
    if (IsNeedLoadLibrary(bundleName)) {
        ChangeToLocalPath(bundleName, appInfo.moduleSourceDirs, localPaths);
        LoadAbilityLibrary(localPaths);
        LoadNativeLiabrary(bundleInfo, appInfo.nativeLibraryPath);
    }
    if (appInfo.needAppDetail) {
        LoadAppDetailAbilityLibrary(appInfo.appDetailAbilityLibraryPath);
    }
    LoadAppLibrary();
    if (isStageBased) {
        AppRecovery::GetInstance().InitApplicationInfo(GetMainHandler(), GetApplicationInfo());
    }
    // create contextImpl
    ......
    if (isStageBased) {
        // Create runtime
        ......
        application_->SetRuntime(std::move(runtime));
        AbilityLoader::GetInstance().RegisterAbility("Ability", [application = application_]() {
            return Ability::Create(application->GetRuntime());
        });
    LoadAllExtensions(jsEngine);
    contextDeal->initResourceManager(resourceManager);
    contextDeal->SetApplicationContext(application_);
    application_->AttachBaseContext(contextDeal);
    application_->SetAbilityRecordMgr(abilityRecordMgr_);
    application_->SetConfiguration(config);
    contextImpl->SetConfiguration(application_->GetConfiguration());

    applicationImpl_->SetRecordId(appLaunchData.GetRecordId());
    applicationImpl_->SetApplication(application_);
    mainThreadState_ = MainThreadState::READY;
    ......
    applicationImpl_->PerformAppReady()
    nwebMgr->PreStartNWebSpawnProcess();
    ......
    // init resourceManager.
    ......
}

3. 通过RunningRecord调用LaunchPendingAbilities,最终创建Ability

foundation\ability\ability_runtime\services\appmgr\src/module_running_record.cpp

void ModuleRunningRecord::LaunchPendingAbilities()
{
    for (const auto &item : abilities_) {
        const auto &ability = item.second;
        if (ability->GetState() == AbilityState::ABILITY_STATE_CREATE && ability->GetToken() &&
            appLifeCycleDeal_->GetApplicationClient()) {
            appLifeCycleDeal_->LaunchAbility(ability);
            ability->SetState(AbilityState::ABILITY_STATE_READY);
        }
    }
}
void ModuleRunningRecord::LaunchAbility(const std::shared_ptr<AbilityRunningRecord> &ability)
{
    appLifeCycleDeal_->LaunchAbility(ability);
    ability->SetState(AbilityState::ABILITY_STATE_READY);
}

通过IPC调用ScheduleLaunchAbility函数
foundation\ability\ability_runtime\services\appmgr\src/app_lifecycle_deal.cpp

AppLifeCycleDeal::LaunchAbility(const std::shared_ptr<AbilityRunningRecord> &ability)
{
    if (appThread_ && ability) {
        appThread_->ScheduleLaunchAbility(*(ability->GetAbilityInfo()), ability->GetToken(),
            ability->GetWant());
    }
}

foundation\ability\ability_runtime\frameworks\native\appkit\app\main_thread.cpp

MainThread::ScheduleLaunchAbility(const AbilityInfo &info, const sptr<IRemoteObject> &token, const std::shared_ptr<AAFwk::Want> &want)
{
    auto task = [weak, abilityRecord]() {
        ...
        auto appThread = weak.promote();
        appThread->HandleLaunchAbility(abilityRecord);
    };
    mainHandler_->PostTask(task);
}
 MainThread::HandleLaunchAbility(const std::shared_ptr<AbilityLocalRecord> &abilityRecord)
 {
    abilityRecordMgr_->SetToken(abilityToken);
    abilityRecordMgr_->AddAbilityRecord(abilityToken, abilityRecord);
    //创建AbilityStage
    std::shared_ptr<AbilityRuntime::Context> stageContext = application_->AddAbilityStage(abilityRecord);
    //启动Ability线程
    AbilityThread::AbilityThreadMain(application_, abilityRecord, stageContext);  
 }

foundation\ability\ability_runtime\frameworks\native\appkit\app\ohos_application.cpp

bool OHOSApplication::AddAbilityStage(const AppExecFwk::HapModuleInfo &hapModuleInfo)
{
     ......
    auto stageContext = std::make_shared<AbilityRuntime::ContextImpl>();
    stageContext->SetParentContext(abilityRuntimeContext_);
    stageContext->InitHapModuleInfo(hapModuleInfo);
    stageContext->SetConfiguration(GetConfiguration());
    auto abilityStage = AbilityRuntime::AbilityStage::Create(runtime_, *moduleInfo);
    abilityStage->Init(stageContext);
    Want want;
    abilityStage->OnCreate(want);
    abilityStages_[hapModuleInfo.moduleName] = abilityStage;
    return true;
}

foundation\ability\ability_runtime\frameworks\native\appkit\ability_runtime\app\ability_stage.cpp

std::shared_ptr<AbilityStage> AbilityStage::Create(
    const std::unique_ptr<Runtime>& runtime, const AppExecFwk::HapModuleInfo& hapModuleInfo)
{
    ......
    switch (runtime->GetLanguage()) {
        case Runtime::Language::JS:
            return JsAbilityStage::Create(runtime, hapModuleInfo);
        default:
            return std::make_shared<AbilityStage>();
    }
}

void AbilityStage::AddAbility(const sptr<IRemoteObject> &token,
    const std::shared_ptr<AppExecFwk::AbilityLocalRecord> &abilityRecord)
{
    ......
    abilityRecords_[token] = abilityRecord;
}

foundation\ability\ability_runtime\frameworks\native\appkit\ability_runtime\app\js_ability_stage.cpp

std::shared_ptr<AbilityStage> JsAbilityStage::Create(){
    auto& jsRuntime = static_cast<JsRuntime&>(*runtime);
    std::string srcPath(hapModuleInfo.name);
    std::string moduleName(hapModuleInfo.moduleName);
    moduleName.append("::").append("AbilityStage");
    ......
    //srcPath.append("/assets/js/");
    //srcPath.append("AbilityStage.abc");
    srcPath.append(hapModuleInfo.srcPath);
    srcPath.append("/AbilityStage.abc");
    auto moduleObj = jsRuntime.LoadModule(moduleName, srcPath, hapModuleInfo.hapPath,
        hapModuleInfo.compileMode == AppExecFwk::CompileMode::ES_MODULE, commonChunkFlag);
    return std::make_shared<JsAbilityStage>(jsRuntime, std::move(moduleObj));
}

void JsAbilityStage::Init(const std::shared_ptr<Context> &context)
{
    AbilityStage::Init(context);
}

void JsAbilityStage::OnCreate(const AAFwk::Want &want) const
{
    AbilityStage::OnCreate(want);
    ......
    auto& nativeEngine = jsRuntime_.GetNativeEngine();
    NativeValue* value = jsAbilityStageObj_->Get();
    nativeEngine.CallFunction(value, methodOnCreate, nullptr, 0);
}
//AbilityStage
void AbilityStage::Init(const std::shared_ptr<Context>& context){
    context_ = context;
}
void AbilityStage::OnCreate(const AAFwk::Want &want) cons{
    HILOG_DEBUG("AbilityStage OnCreate come.");
}

foundation\ability\ability_runtime\frameworks\native\ability\native\ability_thread.cpp


void AbilityThread::AbilityThreadMain(
    std::shared_ptr<OHOSApplication> &application, const std::shared_ptr<AbilityLocalRecord> &abilityRecord,
    const std::shared_ptr<AbilityRuntime::Context> &stageContext){
    //Attach The ability thread to the main process
    thread->Attach(application, abilityRecord, stageContext);
}

void AbilityThread::Attach(
    std::shared_ptr<OHOSApplication> &application, const std::shared_ptr<AbilityLocalRecord> &abilityRecord,
    const std::shared_ptr<AbilityRuntime::Context> &stageContext){
   // 1.new AbilityHandler 根据不同AbilityType获得abilityName
    std::string abilityName = CreateAbilityName(abilityRecord, application);
    runner_ = EventRunner::Create(abilityName);
    abilityHandler_ = std::make_shared<AbilityHandler>(runner_);
    // 2.new ability
    auto ability = AbilityLoader::GetInstance().GetAbilityByName(abilityName);
    currentAbility_.reset(ability);
    token_ = abilityRecord->GetToken();
    abilityRecord->SetEventHandler(abilityHandler_);
    abilityRecord->SetEventRunner(runner_);
    abilityRecord->SetAbilityThread(this);
    ability->AttachBaseContext(contextDeal);
    // new hap requires
    ability->AttachAbilityContext(BuildAbilityContext(abilityRecord->GetAbilityInfo(), application, token_,
        stageContext));
    // 3.new abilityImpl 
    abilityImpl_ = DelayedSingleton<AbilityImplFactory>::GetInstance()->MakeAbilityImplObject(abilityRecord->GetAbilityInfo());
    //Ability初始化操作
    abilityImpl_->Init(application, abilityRecord, currentAbility_, abilityHandler_, token_, contextDeal);
    // 4. ability attach : ipc
    ErrCode err = AbilityManagerClient::GetInstance()->AttachAbilityThread(this, token_);
}

至此,关于应用启动过程中application和ability初始化梳理清楚,OpenHarmony的源码关键Api和源码路径也都列举了出来,有疑问可自行阅读源码加深理解。

四、总结-时序图

写在最后

如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙

  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  • 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
  • 想要获取更多完整鸿蒙最新学习知识点,请移步前往小编:https://gitee.com/MNxiaona/733GH/blob/master/jianshu
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,179评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,229评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,032评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,533评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,531评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,539评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,916评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,813评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,568评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,654评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,354评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,937评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,918评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,152评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,852评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,378评论 2 342

推荐阅读更多精彩内容