A vida passada e presente da capacidade de serviço Hongmeng - capítulo avançado

2. Configuração SA

A operação do SA requer vários itens de configuração, que são explicados especificamente nesta seção.

SA no OpenHarmony geralmente consiste em dois arquivos de configuração e um. O capítulo anterior introduziu a geração de código assim. Esta seção descreve os outros dois arquivos de configuração (.cfg ou .rc, xml).

O SA geralmente é iniciado usando o método .cfg ou .rc + .xml + libxxx.z.so. O processo init do OpenHarmony executa o arquivo xxx.cfg correspondente para abrir o processo SA relevante.

2.1.xml

Conecte-se ao llibtel_core_service.z.so gerado pelo serviço CoreService acima.

O serviceId deste SA é

// foundation\systemabilitymgr\samgr\interfaces\innerkits\samgr_proxy\include\system_ability_definition.h
TELEPHONY_CORE_SERVICE_SYS_ABILITY_ID            = 4010,

Geralmente, o diretório sa_profile é criado no subsistema onde o SA está localizado e o arquivo 4010.xml e BUILD.gn são adicionados. O conteúdo de 4010.xml e BUILD.gn é o seguinte

2.1.1 4001.xml

// base\telephony\core_service\sa_profile\4010.xml
<info>
    <process>telephony</process>
    <systemability> 
        <name>4010</name>
        <libpath>libtel_core_service.z.so</libpath>
        <run-on-create>true</run-on-create>
        <distributed>false</distributed>
        <dump-level>1</dump-level>
    </systemability>
</info>
  • O nome do processo é o espaço do processo no qual o SA será executado. Este campo é obrigatório.
  • Um arquivo xml pode ter apenas um nó. Configurar vários nós causará falha na compilação.
  • O nome é o serviceId correspondente. Os campos obrigatórios
  • É o caminho de carregamento do SA. Os campos obrigatórios
  • : true significa que o SA será cadastrado no samgr após o início do processo, false significa que ele será iniciado sob demanda, ou seja, será iniciado quando outros módulos acessarem o SA. Os campos obrigatórios
  • :true indica que a SA é uma SA distribuída, false indica que ela possui apenas acesso local cross-IPC.
  • : Não pode ser definido. Três tipos podem ser definidos: BootStartPhase, CoreStartPhase e OtherStartPhase (tipo padrão). A prioridade dos três diminui em ordem. Quando o mesmo processo está no mesmo processo, o SA que registra e configura BootStartPhase irá ser puxado primeiro, depois o SA que configura CoreStartPhase e, finalmente, Other Start Phase. Quando todas as SAs de alta prioridade forem iniciadas e registradas, o registro da SA de nível seguinte será iniciado.
  • : Indica o nível suportado pelo hidumper. A configuração padrão é 1.

2.1.2 CONSTRUIR.gn

# base\telephony\core_service\sa_profile\BUILD.gn
import("//build/ohos/sa_profile/sa_profile.gni")

ohos_sa_profile("core_service_sa_profile") {
    
    
  sources = [ "4010.xml" ]
  part_name = "core_service"
}
  • fontes: indica a lista de arquivos xml de SAs que precisam ser configurados no subsistema atual. Pode suportar vários SAs
  • subsystem_name: é o subsistema atual
  • part_name: é o submódulo ao qual pertence o subsistema atual

Por fim, adicione BUILD.gn ao bundle.json do subsistema para participar da compilação.

// base\telephony\core_service\bundle.json
"//base/telephony/core_service:tel_core_service",
"//base/telephony/core_service/sa_profile:core_service_sa_profile",

Após a conclusão da compilação, o caminho de saída gerará um arquivo xml telephony.xml prefixado com o nome do processo.

2.2 .cfg ou .rc

O arquivo de configuração .cfg é usado principalmente em dispositivos L2, e L3-L5 é implementado usando a configuração .rc. Não há muita diferença entre os dois. Este artigo apresenta principalmente L2 cfg.

// base\telephony\core_service\services\etc\init\telephony.cfg
{
    
    
    "jobs" : [{
    
    
            "name" : "early-boot",
            "cmds" : [
                "mkdir /data/service/el1/public/telephony 0711 radio radio",
                "start telephony_sa"
                ]
        }
    ],
    "services" : [{
    
    
            "name" : "telephony_sa",
            "path" : ["/system/bin/sa_main", "/system/profile/telephony.xml"],
            "uid" : "radio",
            "gid" : ["radio", "shell"],
            "permission" : [
                "ohos.permission.COMMONEVENT_STICKY",
                "ohos.permission.CONNECTIVITY_INTERNAL",
                "ohos.permission.GET_TELEPHONY_STATE",
                "ohos.permission.PERMISSION_USED_STATS",
                "ohos.permission.RECEIVE_SMS",
                "ohos.permission.SET_TELEPHONY_STATE",
                "ohos.permission.MANAGE_SECURE_SETTINGS"
            ],
            "secon" : "u:r:telephony_sa:s0"
        }
    ]
}

O arquivo de configuração cfg é a estratégia de pull-up do processo nativo fornecida pelo OpenHarmony.Durante a fase de inicialização do dispositivo, o processo init analisa o arquivo cfg configurado e puxa o dispositivo.

  • O item de configuração jobs é o tipo de ação correspondente à chave, ou seja, após o evento identificado como nome ser satisfeito, as ações configuradas pelo tipo cmds são acionadas. Para parâmetros de configuração específicos, consulte o subsistema de inicialização do OpenHarmony (base/startup /iniciar).
  • Os serviços puxam (fork) o processo para executar o código da entidade para init, e o caminho é o programa executável sa_main e os parâmetros correspondentes. Este xml é o arquivo xml de configuração que precisa ser analisado após o início do processo sa_main.
  • uid, gid, permissão, secon envolvem gerenciamento de permissões de usuário e selinux e serão explicados em um artigo separado quando houver tempo no futuro.

Após a conclusão da configuração, cfg precisa ser adicionado ao BUILD.gn para participar da compilação.

// base\telephony\core_service\services\etc\init\BUILD.gn
import("//build/ohos.gni")

## Install telephony.cfg to /system/etc/init/telephony.cfg
ohos_prebuilt_etc("telephony.cfg") {
    
    
  source = "telephony.cfg"

  relative_install_dir = "init"
  part_name = "core_service"
  subsystem_name = "telephony"
}
// base\telephony\core_service\bundle.json
"//base/telephony/core_service/services/etc/init:telephony.cfg",
  • Se precisar depurar, você pode enviar diretamente o arquivo telephony.cfg para o diretório device/system/etc/init e enviar o arquivo telephony.xml para o diretório device/system/profile. Em seguida, reinicie o telefone e verifique se esse processo foi iniciado através da telefonia ps -ef | grep.
  • Após o processo iniciar normalmente, use hdc shell hidumper -ls para filtrar o referido ID para 1410 e verifique se o SA foi registrado com sucesso. (Se o comando hidumper não for compatível, você mesmo pode compilá-lo e gerá-lo)

3. Ciclo de vida em SA

Insira a descrição da imagem aqui
A imagem acima mostra o ciclo de vida e o diagrama de transição de estado da Habilidade. Neste exemplo, CoreService herda SystemAbility. SystemAbility é um serviço executado em segundo plano. Não há distinção entre front-end e segundo plano. Referindo-se ao código da classe SystemAbility, o ciclo de vida do SA é OnStart, OnStop e OnDump.

Neste ponto, ao implementar o SA, você precisa implementar os três métodos OnStart, OnStop e OnDump na classe de serviço (CoreService) para concluir o término da inicialização do SA e o tratamento de exceções.

4. Retorno de chamada do SA

Como registrar uma função de retorno de chamada no SA e executar a função de retorno de chamada registrada após o serviço do SA concluir determinadas funções.

Como SA é uma comunicação IPC entre processos, a interface SA não pode simplesmente definir um ponteiro de função e chamar de volta esse ponteiro de função. Neste momento, você só precisa implementar uma classe SA de retorno de chamada e definir a classe SA de retorno de chamada como SA. Neste momento, o SA pode retornar a função de retorno de chamada registrada no SA por meio do IPC.

Os elementos de implementação do callback SA são semelhantes à implementação do SA.

  • Definir classe de interface IPC externa

  • Definir classe de proxy de proxy de comunicação do cliente

  • Definir classe de stub de comunicação do lado do servidor

  • Classe de implementação de serviço SA

Tome também como exemplo o CoreService para adicionar uma interface de retorno de chamada. Existe uma interface no CoreService

// base\telephony\core_service\services\core\include\core_service.h
int32_t GetNetworkSearchInformation(int32_t slotId, const sptr<INetworkSearchCallback> &callback) override;

O INetworkSearchCallback passado nesta interface é a primeira classe de interface IPC externa.

4.1 Classe de interface IPC de retorno de chamada

// base\telephony\core_service\interfaces\innerkits\include\i_network_search_callback.h
class INetworkSearchCallback : public IRemoteBroker {
public:
    virtual ~INetworkSearchCallback() = default;
    enum class NetworkSearchCallback {
        GET_AVAILABLE_RESULT = 0,
        GET_NETWORK_MODE_RESULT,
        SET_NETWORK_MODE_RESULT,
        GET_RADIO_STATUS_RESULT,
        SET_RADIO_STATUS_RESULT,
        GET_PREFERRED_NETWORK_MODE_RESULT,
        SET_PREFERRED_NETWORK_MODE_RESULT,
    };
    virtual int32_t OnNetworkSearchCallback(NetworkSearchCallback requestId, MessageParcel &data) = 0;

public:
    DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.Telephony.INetworkSearchCallback");
};

4.2 Classe de proxy de retorno de chamada

// base\telephony\core_service\services\network_search\include\network_search_callback_proxy.h
class NetworkSearchCallBackProxy : public IRemoteProxy<INetworkSearchCallback> {
public:
    explicit NetworkSearchCallBackProxy(const sptr<IRemoteObject> &impl);
    virtual ~NetworkSearchCallBackProxy() = default;
    int32_t OnNetworkSearchCallback(
        NetworkSearchCallback requestId, MessageParcel &callBackParcel) override;

private:
    static inline BrokerDelegator<NetworkSearchCallBackProxy> delegator_;
};

4.3 Classe stub de retorno de chamada

// base\telephony\core_service\interfaces\innerkits\include\i_network_search_callback_stub.h
class INetworkSearchCallbackStub : public IRemoteStub<INetworkSearchCallback> {
public:
    static const int32_t DEFAULT_ERROR = -1;
    static const int32_t DEFAULT_RESULT = 0;
    INetworkSearchCallbackStub() = default;
    virtual ~INetworkSearchCallbackStub() = default;
    int32_t OnNetworkSearchCallback(NetworkSearchCallback requestId, MessageParcel &data) override;
    int OnRemoteRequest(
        uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override final;
    virtual void OnSetNetworkModeCallback(const bool setResult, const int32_t errorCode);
    virtual void OnGetNetworkModeCallback(const int32_t searchModel, const int32_t errorCode);
    virtual void OnSetRadioStateCallback(const bool setResult, const int32_t errorCode);
    virtual void OnGetRadioStateCallback(const bool setResult, const int32_t errorCode);
    virtual void OnGetNetworkSearchInformation(
        const sptr<NetworkSearchResult> &networkSearchResult, const int32_t errorCode);
    virtual void OnSetPreferredNetworkCallback(const bool result, const int32_t errorCode);
    virtual void OnGetPreferredNetworkCallback(const int32_t networkMode, const int32_t errorCode);

private:
    void OnSetNetworkModeCallback(MessageParcel &data);
    void OnGetNetworkModeCallback(MessageParcel &data);
    void OnSetRadioStateCallback(MessageParcel &data);
    void OnGetRadioStateCallback(MessageParcel &data);
    void OnGetNetworkSearchInformation(MessageParcel &data);
    void OnSetPreferredNetworkCallback(MessageParcel &data);
    void OnGetPreferredNetworkCallback(MessageParcel &data);
};

4.4 Classe de implementação do serviço de retorno de chamada

// base\telephony\core_service\frameworks\js\network_search\include\get_network_search_info_callback.h
class GetNetworkSearchInfoCallback : public INetworkSearchCallbackStub {
public:
    explicit GetNetworkSearchInfoCallback(GetSearchInfoContext *context);
    void OnGetNetworkSearchInformation(
        const sptr<NetworkSearchResult> &networkSearchResult, const int32_t errorCode) override;

private:
    GetSearchInfoContext *asyncContext_;
};
// base\telephony\core_service\frameworks\js\network_search\include\get_preferred_network_callback.h
class GetPreferredNetworkCallback : public INetworkSearchCallbackStub {
public:
    explicit GetPreferredNetworkCallback(PreferredNetworkModeContext *asyncContext);
    void OnGetPreferredNetworkCallback(const int32_t networkMode, const int32_t errorCode) override;

private:
    PreferredNetworkModeContext *asyncContext_;
};

4.5 Registro de retorno de chamada SA

// base\telephony\core_service\frameworks\js\network_search\src\napi_radio.cpp
static void NativeGetNetworkSearchInformation(napi_env env, void *data)
{
    auto asyncContext = static_cast<GetSearchInfoContext *>(data);
    if (!IsValidSlotId(asyncContext->slotId)) {
        TELEPHONY_LOGE("NativeGetNetworkSearchInformation slotId is invalid");
        asyncContext->errorCode = ERROR_SLOT_ID_INVALID;
        return;
    }
    std::unique_ptr<GetNetworkSearchInfoCallback> callback =
        std::make_unique<GetNetworkSearchInfoCallback>(asyncContext);
    std::unique_lock<std::mutex> callbackLock(asyncContext->callbackMutex);
    asyncContext->errorCode = DelayedRefSingleton<CoreServiceClient>::GetInstance().GetNetworkSearchInformation(
        asyncContext->slotId, callback.release());
    if (asyncContext->errorCode == TELEPHONY_SUCCESS) {
        asyncContext->cv.wait_for(
            callbackLock, std::chrono::seconds(WAIT_TIME_SECOND), [asyncContext] { return asyncContext->callbackEnd; });
        TELEPHONY_LOGI("NativeGetNetworkSearchInformation after callback end");
    }
    TELEPHONY_LOGI("NativeGetNetworkSearchInformation end");
}

使用方式就比较简单直接 std::make_unique<GetNetworkSearchInfoCallback>(asyncContext);

然后通过CoreService的SA的接口GetNetworkSearchInformation注册回调的SA类GetNetworkSearchInfoCallback进CoreService的SA。到此SA实现了回调方式的IPC调用。

Acho que você gosta

Origin blog.csdn.net/procedurecode/article/details/130228410
Recomendado
Clasificación