0
点赞
收藏
分享

微信扫一扫

SA编写方法【4.0Release】

以沫的窝 04-03 18:30 阅读 1

1 SA简述

SA的全称是system ability,类似于安卓里的service,是一些运行在单独进程的里的服务,可以选择开机运行或者不运行。同一个进程可以运行多个SA,这里介绍的SA仅适用于富设备。

2 IPC模型

SA作为运行在单独进程里的服务,其接口只能基于跨进程通讯方法进行调用(IPC),可以通过提供proxy接口让别的进程快速调用SA的接口,IPC通讯过程中的数据通过序列化接口读写。

2.1 编写interface.h(ifree_sa_test.h)

--javascripttypescriptbashsqljsonhtmlcssccppjavarubypythongorustmarkdown

#include "iremote_broker.h"
class IFreeSaTest : public OHOS::IRemoteBroker {
public:
    DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.FreeSaTest.FreeSaTestService");

    virtual std::string GetName() = 0;
    virtual int32_t SetBalance(int32_t balance) = 0;
    virtual int32_t GetBalance() = 0;
    enum SA_FUN_CODE {
        GET_NAME,
        SET_BALANCE,
        GET_BALANCE
    };
};

DECLARE_INTERFACE_DESCRIPTOR只是用于申明descripor的宏,拿来用就行用就行了

--javascripttypescriptbashsqljsonhtmlcssccppjavarubypythongorustmarkdown

#define DECLARE_INTERFACE_DESCRIPTOR(DESCRIPTOR)                         \
     static constexpr const char16_t *metaDescriptor_ = DESCRIPTOR;       \
     static inline const std::u16string GetDescriptor()                  \
     {                                                                    \
         return metaDescriptor_;                                          \
     }

2.2 编写stub

stub.h

--javascripttypescriptbashsqljsonhtmlcssccppjavarubypythongorustmarkdown

#include "ifree_sa_test.h"
#include "iremote_stub.h"

class IFreeSaTestStub : public IRemoteStub<IFreeSaTest> {
public:
    // 响应客户端请求的入口函数
    int32_t OnRemoteRequest(uint32_t code, MessageParcel& data, MessageParcel& reply,
        MessageOption &option) override;
};

stub.cpp

--javascripttypescriptbashsqljsonhtmlcssccppjavarubypythongorustmarkdown

#include "free_sa_test_stub.h"
int32_t IFreeSaTestStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option)
{
    auto retvalue = 0;
	// 实现的接口多的话可以用map绑定funCode与对应的处理函数,而不用switch
    switch(code)
    {
        case GET_NAME: {
            std::string name = GetName();
			// 通过序列化的方法把数据写到共享内存
            reply.WriteString(name);
        }
        break;
	。。。
        retvalue = IPCObjectStub::OnRemoteRequest(code, data, reply, option);
        break;
    }
	return retvalue ;
}

2.3 编写service

service.h

--javascripttypescriptbashsqljsonhtmlcssccppjavarubypythongorustmarkdown

#include "ipc_skeleton.h"
#include "system_ability.h"
#include "free_sa_test_stub.h"
// service会继承stub,所以stub不是必须的。stub只是把响应(OnRemoteRequest)这个动作独立出来,增加了可读性,建议还是都这么做。
class FreeSaTestService : public SystemAbility, public IFreeSaTestStub {
	// 提供查询类名的接口
    DECLARE_SYSTEM_ABILITY(FreeSaTestService);
	// 删除拷贝构造和移动构造
    DISALLOW_COPY_AND_MOVE(FreeSaTestService);
    explicit FreeSaTestService(int32_t systemAbilityId, bool runOnCreate = true);
    ~FreeSaTestService() override;

private:
    std::string  GetName() override;
    int32_t SetBalance(int32_t balance) override;
    int32_t GetBalance() override;

	// service的基本实现
    void OnStart() override;
    void OnStop() override;

    int32_t m_balance;
};

service.cpp

--javascripttypescriptbashsqljsonhtmlcssccppjavarubypythongorustmarkdown

#include "free_sa_test_service.h"
#include "system_ability_definition.h"

// 这一步是sa注册的宏
// FREE_SA_TEST_SERVICE_1是said,需要将saId和sa_name定义在foundation/systemabilitymgr/samgr/interfaces/innerkits/samgr_proxy/include/system_ability_definition.h里
REGISTER_SYSTEM_ABILITY_BY_ID(FreeSaTestService, FREE_SA_TEST_SERVICE_1, true);

FreeSaTestService::FreeSaTestService(int32_t systemAbilityId, bool runOnCreate)
:SystemAbility(systemAbilityId, runOnCreate), m_balance(0)
{
    HILOGI("Create FreeSaTestService SaId = %{public}d", systemAbilityId);
}
FreeSaTestService::~FreeSaTestService()
{
}
// 自己的功能
std::string FreeSaTestService::GetName()
{
    return "FreeSaTestService1";
}
void FreeSaTestService::OnStart()
{
    bool res = Publish(this);
    if (!res) {
        HILOGE("Publish said = %{public}d failed", FREE_SA_TEST_SERVICE_1);
    }
    return;
}

void FreeSaTestService::OnStop()
{
}
。。。。。

gn

--javascripttypescriptbashsqljsonhtmlcssccppjavarubypythongorustmarkdown

external_deps = [
    "c_utils:utils",
    "ipc:ipc_core",
    "samgr:samgr_proxy",
	"safwk:system_ability_fwk"
  ]

2.4 SA配置文件json

  1. 1.

    进程名字即该SystemAbility要运行的进程空间,此字段是必填选项。
  2. 2.

    一个SystemAbility配置文件只能配置一个SystemAbility节点,配置多个会导致编译失败。
  3. 3.

    SystemAbility的name为对应的serviceId必须与代码中注册的serviceId保持一致,必配项。
  4. 4.

    libpath为SystemAbility的加载路径,必配项。
  5. 5.

    run-on-create:true表示进程启动后即向samgr组件注册该SystemAbility;false表示按需启动,即在其他模块访问到该SystemAbility时启动,必配项。
  6. 6.

    distributed:true表示该SystemAbility为分布式SystemAbility,支持跨设备访问;false表示只有本地跨IPC访问。
  7. 7.

    bootphase:可不设置;可以设置的值有三种:BootStartPhase、CoreStartPhase、OtherStartPhase(默认类型),三种优先级依次降低,当同一个进程中,会优先拉起注册配置BootStartPhase的SystemAbility,然后是配置了CoreStartPhase的SystemAbility,最后是OtherStartPhase;当高优先级的SystemAbility全部启动注册完毕才会启动下一级的SystemAbility的注册启动。
  8. 8.

    dump-level:表示systemdumper支持的level等级,默认配置1。
  9. 9.

    BUILD.gn中subsystem_name为相应部件名称;sources表示当前子系统需要配置的SystemAbility列表,可支持配置多个SystemAbility。
    { "process": "free_sa_test_service", "systemability": [ { "name": 9600, "libpath": "libfree_sa_test_service.z.so", "run-on-create": true, "distributed": false, "dump_level": 1, } ] }

json的编译gn

--javascripttypescriptbashsqljsonhtmlcssccppjavarubypythongorustmarkdown

import("//build/ohos/sa_profile/sa_profile.gni")
ohos_sa_profile("xxx_sa_profile") {
    sources = [
        "serviceid.json"
    ]
    subsystem_name = "systemabilitymgr"
}

2.5 进程配置文件cfg

当前服务的cfg例子:

1.name是进程名

2.path是json

3.uid和gid都是需要指定的。对应的配置文件是base/startup/init/service/etc/group和base/startup/init/service/etc/passwd

4.ondemand,表示是否开机拉起该进程

5.secon,是selinux标签,如果所用标签未定义或者权限不足,进程都无法拉起。如果关闭了selinux,则需要在cfg里删除该字段。

--javascripttypescriptbashsqljsonhtmlcssccppjavarubypythongorustmarkdown

{
    "services" : [{
            "name" : "free_sa_test_service",
            "path" : ["/system/bin/sa_main", "/data/dynamic_sa/9600/free_sa_test_service.json"],
            "uid" : "OpenValleyDynamicSa",
            "gid" : ["OpenValleyDynamicSa", "shell"],
            "ondemand" : false,
            "apl" : "system_basic",
            "secon" : "u:r:openvalley_dynamic_sa:s0"
        }
    ]
}

gn

--javascripttypescriptbashsqljsonhtmlcssccppjavarubypythongorustmarkdown

import("//build/ohos.gni")
	ohos_prebuilt_etc("名称_init") {
	source = "xx.cfg"
	relative_install_dir = "init"
	part_name = 模块名
	subsystem_name = 子系统名
}

2.6 proxy

直至2.5,service已经可以起来了 。proxy是提供一些接口给使用者,让使用者可以方便地调用该服务的接口

proxy.h

--javascripttypescriptbashsqljsonhtmlcssccppjavarubypythongorustmarkdown

#include "iremote_proxy.h"
#include "ifree_sa_test.h"
class FreeSaTestProxy : public IRemoteProxy<IFreeSaTest> {
public: 
    explicit FreeSaTestProxy (const sptr<IRemoteObject>& impl)
        : IRemoteProxy<IFreeSaTest>(impl) {}
	virtual std::string GetName();
    virtual int32_t SetBalance(int32_t balance);
    virtual int32_t GetBalance();
	// 如果想使用iface_cast转化得到该proxy,则必须初始化这个代理变量,将这个proxy类型注册到BrokerRegistration
	static inline BrokerDelegator<FreeSaTestProxy > delegator_;
}

proxy.cpp

--javascripttypescriptbashsqljsonhtmlcssccppjavarubypythongorustmarkdown

#include "free_sa_test_proxy.h"
std::string FreeSaTestProxy::GetName() 
{
    sptr<IRemoteObject> remote = Remote();
    MessageParcel data;
    MessageParcel reply;
    MessageOption option;
	int32_t err= remote->SendRequest(GET_NAME, data, reply, option);
	if (err != ERR_NONE) {
        HILOGE("InstallDynamicSystemAbility SendRequest error: %{public}d!", err);
        return err;
    }
	auto str = reply.ReadString();
	return str;
}
。。。。

gn

--javascripttypescriptbashsqljsonhtmlcssccppjavarubypythongorustmarkdown

external_deps = [
    "c_utils:utils",
    "ipc:ipc_core",
    "samgr:samgr_proxy",
]

2.7 使用

然后在任意地方使用即可

--javascripttypescriptbashsqljsonhtmlcssccppjavarubypythongorustmarkdown

auto systemManager =
        SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
    auto object = systemManager->GetSystemAbility(FREE_SA_TEST_SERVICE_1);
    if (object == nullptr) {
        HILOGE("Get service %{public}d failed", FREE_SA_TEST_SERVICE_1);
        return nullptr;
    }
    Proxy_ = iface_cast<ISystemAbilityLoader>(object);
    if (Proxy_ == nullptr) {
        HILOGE("iface_cast to proxy failed");
        return nullptr;
    }

举报

相关推荐

0 条评论