feat: add plugin engine for init.

1)通过ohos_native_stub_library为init提供libinit_plugin_engine打桩库,解决插件的编译链接问题。
2)通过ohos_native_stub_versionscript为init进程export开放API供插件调用。
3)通过libinit_stub_empty创建空的so库解决dlopen插件时找不到库的问题。

Signed-off-by: handyohos <zhangxiaotian@huawei.com>
Change-Id: I631723ce7a388d5f2067edf12068f7eb1e4c21da
This commit is contained in:
handyohos 2022-04-21 20:31:28 +08:00
parent c52d3ee6ab
commit cce477f89f
17 changed files with 112 additions and 175 deletions

12
bundle.json Normal file → Executable file
View File

@ -48,7 +48,8 @@
"//base/startup/init_lite/interfaces/innerkits/file:libfile",
"//base/startup/init_lite/interfaces/innerkits/socket:libsocket",
"//base/startup/init_lite/services/loopevent:loopevent",
"//base/startup/init_lite/interfaces/innerkits/plugin:libplugin",
"//base/startup/init_lite/services/init/plugin_engine:libinit_plugin_engine",
"//base/startup/init_lite/services/init/plugin_engine:libinit_stub_empty",
"//base/startup/init_lite/device_info:device_info_group",
"//base/startup/init_lite/interfaces/innerkits/sandbox:libsandbox"
],
@ -76,6 +77,15 @@
]
},
"name": "//base/startup/init_lite/interfaces/innerkits:libbeget_proxy"
},
{
"header": {
"header_base": "//base/startup/init_lite/services/init/plugin_engine/include",
"header_files": [
"init_plugin_engine.h"
]
},
"name": "//base/startup/init_lite/services/init/plugin_engine:libinit_plugin_engine"
}
],
"test": [

View File

@ -1,27 +0,0 @@
# Copyright (c) 2021 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//build/ohos.gni")
ohos_shared_library("libplugin") {
sources = [ "init_plugin.c" ]
include_dirs = [
"//base/startup/init_lite/interfaces/innerkits/include",
"//base/startup/init_lite/services/log",
]
deps = [ "//third_party/bounds_checking_function:libsec_static" ]
install_enable = true
part_name = "init"
}

View File

@ -1,21 +0,0 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "init_plugin.h"
static PluginInterface g_pluginInterface = {};
PluginInterface *GetPluginInterface(void)
{
return &g_pluginInterface;
}

8
services/BUILD.gn Normal file → Executable file
View File

@ -102,6 +102,7 @@ if (defined(ohos_lite)) {
} else {
import("//base/startup/init_lite/begetd.gni")
import("//build/ohos.gni")
import("//build/ohos/native_stub/native_stub.gni")
ohos_executable("init") {
sources = [
@ -155,6 +156,8 @@ if (defined(ohos_lite)) {
"//third_party/cJSON:cjson_static",
]
deps += [ "//base/startup/init_lite/services/init/plugin_engine:libinit_stub_versionscript" ]
cflags = []
if (use_musl) {
@ -195,6 +198,11 @@ if (defined(ohos_lite)) {
if (defined(product_name) && product_name == "rk3568") {
defines += [ "PRODUCT_RK" ]
}
version_script = get_label_info(
"//base/startup/init_lite/services/init/plugin_engine:libinit_stub_versionscript",
"target_gen_dir") + "/" + get_label_info(
"//base/startup/init_lite/services/init/plugin_engine:libinit_stub_versionscript",
"name") + stub_version_script_suffix
defines += [ "_GNU_SOURCE" ]
install_images = [
"system",

4
services/init/include/init_plugin_manager.h Normal file → Executable file
View File

@ -17,7 +17,6 @@
#include <stdlib.h>
#include <string.h>
#include "init_plugin.h"
#include "list.h"
#ifdef __cplusplus
@ -72,8 +71,7 @@ void PluginManagerInit(void);
int AddCmdExecutor(const char *cmdName, CmdExecutor execCmd);
int ParseInitCfg(const char *configFile, void *context);
typedef PluginInterface *(*GetPluginInterfaceFunc)();
int SetPluginInterface(void);
#ifdef __cplusplus
#if __cplusplus
}

View File

@ -0,0 +1,38 @@
# Copyright (c) 2021 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//build/ohos.gni")
import("//build/ohos/native_stub/native_stub.gni")
config("libinit_plugin_engine_config") {
include_dirs =
[ "//base/startup/init_lite/services/init/plugin_engine/include" ]
}
ohos_native_stub_library("libinit_plugin_engine") {
output_extension = "so"
public_configs = [ ":libinit_plugin_engine_config" ]
stub_description_file = "./stub/libinit.stub.json"
}
ohos_native_stub_versionscript("libinit_stub_versionscript") {
stub_description_file = "./stub/libinit.stub.json"
}
ohos_native_stub_library("libinit_stub_empty") {
output_extension = "so"
stub_description_file = "./stub/libinit.stub.empty.json"
part_name = "init"
install_enable = true
symlink_target_name = [ "libinit_plugin_engine.so" ]
}

View File

@ -26,17 +26,18 @@ extern "C" {
#define PLUGIN_CONSTRUCTOR(void) static void _init(void) __attribute__((constructor)); static void _init(void)
#define PLUGIN_DESTRUCTOR(void) static void _destroy(void) __attribute__((destructor)); static void _destroy(void)
typedef struct {
int (*pluginRegister)(const char *name, const char *config, int (*pluginInit)(void), void (*pluginExit)(void));
int (*addCmdExecutor)(const char *cmdName,
int (*CmdExecutor)(int id, const char *name, int argc, const char **argv));
void (*removeCmdExecutor)(const char *cmdName, int id);
int (*systemWriteParam)(const char *name, const char *value);
int (*systemReadParam)(const char *name, char *value, unsigned int *len);
int (*securityLabelSet)(const char *name, const char *label, const char *paraType);
} PluginInterface;
int SystemWriteParam(const char *name, const char *value);
int SystemReadParam(const char *name, char *value, unsigned int *len);
typedef int (*CmdExecutor)(int id, const char *name, int argc, const char **argv);
int AddCmdExecutor(const char *cmdName, CmdExecutor execCmd);
void RemoveCmdExecutor(const char *cmdName, int id);
int PluginRegister(const char *name, const char *config, int (*pluginInit)(void), void (*pluginExit)(void));
PluginInterface *GetPluginInterface(void);
#ifdef __cplusplus
#if __cplusplus
}

View File

@ -0,0 +1,2 @@
[
]

View File

@ -0,0 +1,7 @@
[
{ "name": "SystemWriteParam" },
{ "name": "SystemReadParam" },
{ "name": "AddCmdExecutor" },
{ "name": "RemoveCmdExecutor" },
{ "name": "PluginRegister" }
]

46
services/init/standard/init_plugin_manager.c Normal file → Executable file
View File

@ -21,7 +21,6 @@
#include "init_utils.h"
#include "init_log.h"
#include "init_group_manager.h"
#include "init_plugin.h"
#include "init_service_manager.h"
#include "securec.h"
@ -59,7 +58,7 @@ int AddCmdExecutor(const char *cmdName, CmdExecutor execCmd)
return cmdExec->id;
}
static void RemoveCmdExecutor(const char *cmdName, int id)
void RemoveCmdExecutor(const char *cmdName, int id)
{
INIT_ERROR_CHECK(cmdName != NULL, return, "Invalid input param");
InitGroupNode *groupNode = GetGroupNode(NODE_TYPE_CMDS, cmdName);
@ -273,7 +272,7 @@ static PluginInfo *GetPluginInfo(const char *name)
return info;
}
static int PluginRegister(const char *name, const char *config, int (*pluginInit)(void), void (*pluginExit)(void))
int PluginRegister(const char *name, const char *config, int (*pluginInit)(void), void (*pluginExit)(void))
{
INIT_LOGI("PluginRegister %s %p %p", name, pluginInit, pluginExit);
INIT_ERROR_CHECK(name != NULL, return -1, "Invalid plugin name");
@ -364,47 +363,6 @@ void PluginManagerInit(void)
// "ohos.servicectrl.install"
(void)AddCmdExecutor("install", PluginCmdInstall);
(void)AddCmdExecutor("uninstall", PluginCmdUninstall);
// register interface
SetPluginInterface();
// read cfg and start static plugin
LoadPluginCfg();
}
int SetPluginInterface(void)
{
static PluginInterface *pluginInterface = NULL;
if (pluginInterface != NULL) {
return 0;
}
char *realPath = GetRealPath("/system/lib/libplugin.z.so");
#ifndef STARTUP_INIT_TEST
void* handle = dlopen(realPath, RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE);
if (handle == NULL) {
INIT_LOGE("Failed to load module %s, err %s", realPath, dlerror());
free(realPath);
return -1;
}
GetPluginInterfaceFunc getPluginInterface = (GetPluginInterfaceFunc)dlsym(handle, "GetPluginInterface");
#else
GetPluginInterfaceFunc getPluginInterface = GetPluginInterface;
#endif
INIT_LOGI("PluginManagerInit getPluginInterface %p ", getPluginInterface);
if (getPluginInterface != NULL) {
pluginInterface = getPluginInterface();
if (pluginInterface != NULL) {
pluginInterface->pluginRegister = PluginRegister;
pluginInterface->addCmdExecutor = AddCmdExecutor;
pluginInterface->removeCmdExecutor = RemoveCmdExecutor;
pluginInterface->systemWriteParam = SystemWriteParam;
pluginInterface->systemReadParam = SystemReadParam;
pluginInterface->securityLabelSet = NULL;
}
INIT_LOGI("PluginManagerInit pluginInterface %p %p %p",
pluginInterface, pluginInterface->pluginRegister, getPluginInterface);
}
free(realPath);
#ifndef STARTUP_INIT_TEST
dlclose(handle);
#endif
return 0;
}

3
services/plugin/BUILD.gn Normal file → Executable file
View File

@ -27,13 +27,14 @@ ohos_shared_library("libbootchart") {
]
deps = [
"//base/startup/init_lite/interfaces/innerkits/plugin:libplugin",
"//base/startup/init_lite/services/log:init_log",
"//base/startup/init_lite/services/utils:libinit_utils",
"//third_party/bounds_checking_function:libsec_static",
"//third_party/cJSON:cjson_static",
]
external_deps = [ "init:libinit_plugin_engine" ]
part_name = "init"
module_install_dir = "lib/plugin"
}

34
services/plugin/bootchart/bootchart.c Normal file → Executable file
View File

@ -22,7 +22,7 @@
#include <time.h>
#include <unistd.h>
#include "init_plugin.h"
#include "init_plugin_engine.h"
#include "init_param.h"
#include "init_utils.h"
#include "plugin_adapter.h"
@ -31,7 +31,6 @@
#define NANO_PRE_JIFFY 10000000
static BootchartCtrl *g_bootchartCtrl = NULL;
static PluginInterface *g_pluginInterface = NULL;
static long long GetJiffies(void)
{
@ -79,9 +78,7 @@ static void BootchartLogHeader(void)
char release[PARAM_VALUE_LEN_MAX] = {};
uint32_t len = sizeof(release);
if (g_pluginInterface->systemReadParam != NULL) {
(void)g_pluginInterface->systemReadParam("hw_sc.build.os.releasetype", release, &len);
}
(void)SystemReadParam("hw_sc.build.os.releasetype", release, &len);
char *cmdLine = ReadFileToBuffer("/proc/cmdline", g_bootchartCtrl->buffer, g_bootchartCtrl->bufferSize);
PLUGIN_CHECK(cmdLine != NULL, return, "Failed to open file /data/bootchart/header");
@ -222,15 +219,9 @@ static void BootchartDestory(void)
static int DoBootchartStart(void)
{
if (g_pluginInterface == NULL) {
PLUGIN_LOGI("Invalid bootchart plugin");
return -1;
}
char enable[4] = {}; // 4 enable size
uint32_t size = sizeof(enable);
if (g_pluginInterface->systemReadParam != NULL) {
g_pluginInterface->systemReadParam("init.bootchart.enabled", enable, &size);
}
SystemReadParam("init.bootchart.enabled", enable, &size);
if (strcmp(enable, "1") != 0) {
PLUGIN_LOGI("Not bootcharting");
return 0;
@ -298,13 +289,8 @@ static PluginCmd g_bootchartCmds[] = {
static int BootchartInit(void)
{
PLUGIN_LOGI("BootchartInit ");
g_pluginInterface = GetPluginInterface();
PLUGIN_CHECK(g_pluginInterface != NULL && g_pluginInterface->addCmdExecutor != NULL, return -1,
"Invalid install parameter");
for (int i = 0; i < (int)(sizeof(g_bootchartCmds) / sizeof(g_bootchartCmds[0])); i++) {
g_bootchartCmds[i].index = g_pluginInterface->addCmdExecutor(
g_bootchartCmds[i].index = AddCmdExecutor(
g_bootchartCmds[i].name, g_bootchartCmds[i].cmdExecutor);
PLUGIN_LOGI("BootchartInit %d", g_bootchartCmds[i].index);
}
@ -314,20 +300,14 @@ static int BootchartInit(void)
static void BootchartExit(void)
{
PLUGIN_LOGI("BootchartExit %d", g_bootchartCmds[0]);
PLUGIN_CHECK(g_pluginInterface != NULL && g_pluginInterface->removeCmdExecutor != NULL, return,
"Invalid install parameter");
for (int i = 0; i < (int)(sizeof(g_bootchartCmds) / sizeof(g_bootchartCmds[0])); i++) {
g_pluginInterface->removeCmdExecutor(g_bootchartCmds[i].name, g_bootchartCmds[i].index);
RemoveCmdExecutor(g_bootchartCmds[i].name, g_bootchartCmds[i].index);
}
}
PLUGIN_CONSTRUCTOR(void)
{
g_pluginInterface = GetPluginInterface();
if (g_pluginInterface != NULL && g_pluginInterface->pluginRegister != NULL) {
g_pluginInterface->pluginRegister("bootchart", NULL, BootchartInit, BootchartExit);
}
PLUGIN_LOGI("bootchart pluginInterface %p %p %p",
g_pluginInterface, g_pluginInterface->pluginRegister, GetPluginInterface,
PluginRegister("bootchart", NULL, BootchartInit, BootchartExit);
PLUGIN_LOGI("bootchart pluginInterface %p %p",
BootchartInit, BootchartExit);
}

4
test/plugintest/BUILD.gn Normal file → Executable file
View File

@ -30,11 +30,13 @@ ohos_shared_library("libpluginparamtest") {
]
deps = [
"//base/startup/init_lite/interfaces/innerkits/plugin:libplugin",
"//base/startup/init_lite/services/log:agent_log",
"//base/startup/init_lite/services/utils:libinit_tools",
"//third_party/bounds_checking_function:libsec_static",
]
external_deps = [ "init:libinit_plugin_engine" ]
part_name = "init"
module_install_dir = "lib/plugin"
}

0
test/plugintest/plugin_param_cmd.c Normal file → Executable file
View File

26
test/plugintest/plugin_param_test.c Normal file → Executable file
View File

@ -18,18 +18,15 @@
#include "plugin_test.h"
#include "init_param.h"
#include "init_plugin.h"
#include "init_plugin_engine.h"
#define MAX_COUNT 1000
#define TEST_CMD_NAME "param_randrom_write"
static PluginInterface *g_pluginInterface = NULL;
static int g_testCmdIndex = 0;
static int PluginParamCmdWriteParam(int id, const char *name, int argc, const char **argv)
{
PLUGIN_LOGI("PluginParamCmdWriteParam %d %s", id, name);
PLUGIN_CHECK(argv != NULL && argc >= 1, return -1, "Invalid install parameter");
PLUGIN_CHECK(g_pluginInterface != NULL && g_pluginInterface->systemWriteParam != NULL,
return -1, "Invalid install parameter");
PLUGIN_LOGI("PluginParamCmdWriteParam argc %d %s", argc, argv[0]);
int maxCount = MAX_COUNT;
if (argc > 1) {
@ -42,7 +39,7 @@ static int PluginParamCmdWriteParam(int id, const char *name, int argc, const ch
const int wait = READ_DURATION + READ_DURATION; // 100ms
int ret = sprintf_s(buffer, sizeof(buffer), "%d", count);
if (ret > 0) {
g_pluginInterface->systemWriteParam(argv[0], buffer);
SystemWriteParam(argv[0], buffer);
usleep(wait);
}
count++;
@ -52,30 +49,21 @@ static int PluginParamCmdWriteParam(int id, const char *name, int argc, const ch
static int PluginParamTestInit(void)
{
g_pluginInterface = GetPluginInterface();
PLUGIN_CHECK(g_pluginInterface != NULL && g_pluginInterface->addCmdExecutor != NULL,
return -1, "Invalid install parameter");
g_testCmdIndex = g_pluginInterface->addCmdExecutor(TEST_CMD_NAME, PluginParamCmdWriteParam);
g_testCmdIndex = AddCmdExecutor(TEST_CMD_NAME, PluginParamCmdWriteParam);
PLUGIN_LOGI("PluginParamTestInit %d", g_testCmdIndex);
return 0;
}
static void PluginParamTestExit(void)
{
PLUGIN_LOGI("PluginParamTestExit %d", g_testCmdIndex);
PLUGIN_CHECK(g_pluginInterface != NULL && g_pluginInterface->removeCmdExecutor != NULL,
return, "Invalid install parameter");
g_pluginInterface->removeCmdExecutor(TEST_CMD_NAME, g_testCmdIndex);
RemoveCmdExecutor(TEST_CMD_NAME, g_testCmdIndex);
}
PLUGIN_CONSTRUCTOR(void)
{
g_pluginInterface = GetPluginInterface();
if (g_pluginInterface != NULL && g_pluginInterface->pluginRegister != NULL) {
g_pluginInterface->pluginRegister("pluginparamtest",
PluginRegister("pluginparamtest",
"/system/etc/plugin/plugin_param_test.cfg",
PluginParamTestInit, PluginParamTestExit);
}
PLUGIN_LOGI("PLUGIN_CONSTRUCTOR pluginInterface %p %p %p",
g_pluginInterface, g_pluginInterface->pluginRegister, GetPluginInterface);
PLUGIN_LOGI("PLUGIN_CONSTRUCTOR pluginInterface %p",
g_pluginInterface->pluginRegister);
}

6
test/unittest/BUILD.gn Normal file → Executable file
View File

@ -36,7 +36,6 @@ ohos_unittest("init_ut") {
"//base/startup/init_lite/interfaces/innerkits/file/init_file.c",
"//base/startup/init_lite/interfaces/innerkits/fs_manager/fstab.c",
"//base/startup/init_lite/interfaces/innerkits/fs_manager/fstab_mount.c",
"//base/startup/init_lite/interfaces/innerkits/plugin/init_plugin.c",
"//base/startup/init_lite/interfaces/innerkits/reboot/init_reboot_innerkits.c",
"//base/startup/init_lite/interfaces/innerkits/sandbox/sandbox.c",
"//base/startup/init_lite/interfaces/innerkits/sandbox/sandbox_namespace.c",
@ -197,7 +196,10 @@ ohos_unittest("init_ut") {
]
defines += [ "_GNU_SOURCE" ]
external_deps = [ "hiviewdfx_hilog_native:libhilog" ]
external_deps = [
"hiviewdfx_hilog_native:libhilog",
"init:libinit_plugin_engine",
]
if (param_feature_watcher) {
external_deps += [

28
test/unittest/init/plugin_unittest.cpp Normal file → Executable file
View File

@ -16,7 +16,7 @@
#include "init_group_manager.h"
#include "init_hashmap.h"
#include "init_param.h"
#include "init_plugin.h"
#include "init_plugin_engine.h"
#include "init_plugin_manager.h"
#include "init_unittest.h"
#include "init_utils.h"
@ -45,19 +45,16 @@ int TestCmdExecutor(int id, const char *name, int argc, const char **argv)
HWTEST_F(PluginUnitTest, PluginAddCmd, TestSize.Level1)
{
InitServiceSpace();
SetPluginInterface();
PluginManagerInit();
PluginInterface *pluginInterface = GetPluginInterface();
ASSERT_NE(pluginInterface, nullptr);
const char *testName = "testCmd1";
const char *cmdContent = "testCmd1 test1 test2 test3";
int cmdExecId1 = pluginInterface->addCmdExecutor(testName, TestCmdExecutor);
int cmdExecId1 = AddCmdExecutor(testName, TestCmdExecutor);
ASSERT_NE(cmdExecId1 > 0, 0);
int cmdExecId2 = pluginInterface->addCmdExecutor("testCmd2", TestCmdExecutor);
int cmdExecId2 = AddCmdExecutor("testCmd2", TestCmdExecutor);
ASSERT_NE(cmdExecId2 > 0, 0);
cmdExecId2 = pluginInterface->addCmdExecutor("testCmd3", TestCmdExecutor);
cmdExecId2 = AddCmdExecutor("testCmd3", TestCmdExecutor);
ASSERT_NE(cmdExecId2 > 0, 0);
int cmdExecId4 = pluginInterface->addCmdExecutor("testCmd4", TestCmdExecutor);
int cmdExecId4 = AddCmdExecutor("testCmd4", TestCmdExecutor);
ASSERT_NE(cmdExecId4 > 0, 0);
int cmdIndex = 0;
@ -74,31 +71,24 @@ HWTEST_F(PluginUnitTest, PluginAddCmd, TestSize.Level1)
ASSERT_EQ(cmdExecId1, g_cmdExecId);
// del
pluginInterface->removeCmdExecutor("testCmd4", cmdExecId4);
RemoveCmdExecutor("testCmd4", cmdExecId4);
}
static int PluginTestInit(void)
{
PluginInterface *pluginInterface = GetPluginInterface();
if (pluginInterface != nullptr && pluginInterface->addCmdExecutor != nullptr) {
g_cmdExecId = pluginInterface->addCmdExecutor("testCmd4", TestCmdExecutor);
}
g_cmdExecId = AddCmdExecutor("testCmd4", TestCmdExecutor);
return 0;
}
static void PluginTestExit(void)
{
PluginInterface *pluginInterface = GetPluginInterface();
ASSERT_NE(pluginInterface, nullptr);
pluginInterface->removeCmdExecutor("testCmd4", g_cmdExecId);
RemoveCmdExecutor("testCmd4", g_cmdExecId);
}
HWTEST_F(PluginUnitTest, PluginInstallTest, TestSize.Level1)
{
PluginInterface *pluginInterface = GetPluginInterface();
ASSERT_NE(pluginInterface, nullptr);
const char *moduleName = "testplugin";
pluginInterface->pluginRegister(moduleName,
PluginRegister(moduleName,
"/home/axw/init_ut/etc/init/plugin_param_test.cfg",
PluginTestInit, PluginTestExit);
PluginInstall(moduleName, NULL);