OpenHarmony的系统服务(System Ability)提供系统基础能力,伴随着OH的版本演进和功能的不断扩展,SA的数量也越来越多,内存占用也不断膨胀。OpenHarmony框架支持SA的按需启动和卸载,这样可以避免使用频率不高的服务常驻内存,造成系统资源浪费。

目前可配置SA的启停条件有:

  • 设备上下线 如 deviceonline: on|off|ready

  • 设置开关 如 wifi_status:on|off

  • 系统参数

  • 系统公共事件

  • 定时任务

这里我们以update_sa为例来分析如何实现按需启停,update_sa是系统更新升级服务,其功能包括可用更新检查、系统包下载安装等,显然这个服务是不需要常驻的,只要定期进行版本检查,并且在完成安装包下载的下一次开机时保证服务是启动的即可进行系统升级。当前OpenHarmony中update_sa的启动策略是:开机事件拉起,空闲卸载,周期拉起检查版本更新。

要实现按需启停服务,第一步是将服务的同名cfg文件的”ondemand“属性配置为true,对于updater_sa服务来说就是updater_sa.cfg

"services" : [{
            "name" : "updater_sa",
            "path" : ["/system/bin/sa_main", "/system/profile/updater_sa.json"],
            "ondemand" : true,
            "uid" : "update",
            "gid" : ["update", "netsys_socket"],
            "permission" : [
                "ohos.permission.UPDATE_SYSTEM",
                "ohos.permission.GET_NETWORK_INFO"
            ],
            "secon" : "u:r:updater_sa:s0"
        }
    ]

接着我们要设置服务的按需启停条件,按需启停条件在服务的sa_profile里配置,对于updater_sa来说是3006.json

{
  "process": "updater_sa",
  "systemability": [
    {
      "name": 3006,
      "libpath": "libupdateservice.z.so",
      "run-on-create": false,
      "distributed": false,
      "bootphase": "BootStartPhase",
      "dump-level": 1,
      "auto-restart" : true,
      "start-on-demand": {
        "allow-update": true,
        "commonevent": [
          {
            "name": "usual.event.BOOT_COMPLETED"
          }
        ],
        "timedevent": [
          {
            "name": "loopevent",
            "value": "14400"
          }
        ]
      }
    }
  ]
}

上面的配置文件中,“run-on-create":false 说明updater_sa并不在进程启动的同时加载,”start-on-demand“块中定义的就是按需启动的条件,这里定义了两个启动条件,一个是系统公共事件"usual.event.BOOT_COMPLETED",一个是循环定时器事件(该事件每14400秒发一次,也就是4小时一次),这两个事件中的任何一个发生时,系统的SA管理服务会将updater_sa拉起。

如果updater_sa启动后常驻内存,或者updater_sa不提供外部接口,那么我们像上面这样配置完按需启动就可以了。但是实际我们的目的是降低系统资源占用,我们会在服务空闲的时候将服务卸载,并且,在base/update/updateservice/interfaces/inner_api/include/update_service_kits.h中我们可以看到updater_sa还提供了很多外部接口:

class UpdateServiceKits {
public:
    ...
    virtual int32_t RegisterUpdateCallback(const UpgradeInfo &info, const UpdateCallbackInfo &cb) = 0;
    virtual int32_t UnregisterUpdateCallback(const UpgradeInfo &info) = 0;
    virtual int32_t CheckNewVersion(const UpgradeInfo &info, BusinessError &businessError,
        CheckResult &checkResult) = 0;
    virtual int32_t Download(const UpgradeInfo &info, const VersionDigestInfo &versionDigestInfo,
        const DownloadOptions &downloadOptions, BusinessError &businessError) = 0;
    virtual int32_t PauseDownload(const UpgradeInfo &info, const VersionDigestInfo &versionDigestInfo,
        const PauseDownloadOptions &pauseDownloadOptions, BusinessError &businessError) = 0;
    virtual int32_t ResumeDownload(const UpgradeInfo &info, const VersionDigestInfo &versionDigestInfo,
        const ResumeDownloadOptions &resumeDownloadOptions, BusinessError &businessError) = 0;
    ...
};

既然我们提供了对外接口,我们就要保证这些接口可用性,而updater_sa会在空闲时卸载,那么我们还必须提供一种机制,在接口被使用时,如果服务未启动,先拉起updater_sa服务,然后再往下执行原有接口逻辑。

// base/update/updateservice/interfaces/inner_api/engine/update_service_kits_impl.cpp
int32_t UpdateServiceKitsImpl::Download(const UpgradeInfo &info, const VersionDigestInfo &versionDigestInfo,
    const DownloadOptions &downloadOptions, BusinessError &businessError)
{
    ENGINE_LOGI("UpdateServiceKitsImpl::Download");
    auto updateService = GetService();
    RETURN_FAIL_WHEN_SERVICE_NULL(updateService);
    return updateService->Download(info, versionDigestInfo, downloadOptions, businessError);
}
​
// base/update/updateservice/interfaces/inner_api/common/include/base_service_kits_impl.h
template <typename SERVICE> sptr<SERVICE> BaseServiceKitsImpl<SERVICE>::GetService()
{
    ENGINE_LOGI("GetService entry");
    std::lock_guard<std::mutex> lock(remoteServerLock_);
    
    // remoteServer_保存的时服务remote对象的指针,会在服务拉起时初始化,卸载时置为nullptr,如果不为空说明服务已启动,直接返回即可
    if (remoteServer_ != nullptr) {
        return remoteServer_;
    }
    
    // 否则开始拉起流程
    ENGINE_LOGI("GetService recreate service instance");
    // 获取samanager客户端指针
    sptr<ISystemAbilityManager> manager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
    ENGINE_CHECK(manager != nullptr, return nullptr, "manager is nullptr");
    // 检查我们的服务是否已经启动
    sptr<IRemoteObject> object = manager->CheckSystemAbility(systemAbilityId_);
    if (object == nullptr) {
        // 如果未启动调用TryLoadSa(systemAbilityId_)拉起服务
        ENGINE_CHECK(LoadSaService::GetInstance()->TryLoadSa(systemAbilityId_), return nullptr, "TryLoadSa fail");
        object = manager->GetSystemAbility(systemAbilityId_);
        ENGINE_CHECK(object != nullptr, return nullptr, "Get  remote object from samgr failed");
    }
    // 注册死亡回调
    AddDeathRecipient(object);
    // 保存服务server指针
    remoteServer_ = iface_cast<SERVICE>(object);
    ENGINE_CHECK(remoteServer_ != nullptr, return nullptr, "service iface_cast failed");
    // 注册回调
    RegisterCallback();
    return remoteServer_;
}
​
// base/update/updateservice/interfaces/inner_api/common/src/load_sa_service.cpp
bool LoadSaService::TryLoadSa(int systemAbilityId)
{
    InitStatus();
    return LoadSa(systemAbilityId);
}
​
bool LoadSaService::LoadSa(int systemAbilityId)
{
    sptr<ISystemAbilityManager> sm = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
    if (sm == nullptr) {
        ENGINE_LOGE("samgr object null!");
        return false;
    }
    // 调用samanager的LoadSystemAbility函数拉起服务
    int32_t result = sm->LoadSystemAbility(systemAbilityId, this);
    if (result != ERR_OK) {
        ENGINE_LOGE("systemAbilityId: %{public}d, load failed, result code: %{public}d", systemAbilityId, result);
        return false;
    }
    if (!CheckSaLoaded()) {
        ENGINE_LOGE("systemAbilityId: %{public}d, CheckSaLoaded failed", systemAbilityId);
        return false;
    }
    ENGINE_LOGI("systemAbilityId: %{public}d, load succeed", systemAbilityId);
    return true;
}

上面以Download接口为例,实现了调用时拉起updater_sa服务。对每个接口重复上述操作,至此我们已完成了对updater_sa按需启动的适配。

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐