未验证 提交 6b4e30fd 编写于 作者: O openharmony_ci 提交者: Gitee

!607 optimize module manager and hook manager

Merge pull request !607 from handy/0512
......@@ -41,15 +41,15 @@
"//base/startup/init_lite/watchdog:watchdog",
"//base/startup/init_lite/services/begetctl:begetctl",
"//base/startup/init_lite/services/begetctl:paramshell",
"//base/startup/init_lite/services/plugin:plugin",
"//base/startup/init_lite/services/modules:modules",
"//base/startup/init_lite/interfaces/innerkits:libbegetutil",
"//base/startup/init_lite/interfaces/kits/syscap:deviceinfo_ndk",
"//base/startup/init_lite/interfaces/innerkits:libbeget_proxy",
"//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/services/init/plugin_engine:libinit_plugin_engine",
"//base/startup/init_lite/services/init/plugin_engine:libinit_stub_empty",
"//base/startup/init_lite/services/init/module_engine:libinit_module_engine",
"//base/startup/init_lite/services/init/module_engine:libinit_stub_empty",
"//base/startup/init_lite/device_info:device_info_group",
"//base/startup/init_lite/interfaces/innerkits/sandbox:libsandbox"
],
......@@ -87,12 +87,12 @@
},
{
"header": {
"header_base": "//base/startup/init_lite/services/init/plugin_engine/include",
"header_base": "//base/startup/init_lite/services/init/module_engine/include",
"header_files": [
"init_plugin_engine.h"
"init_module_engine.h"
]
},
"name": "//base/startup/init_lite/services/init/plugin_engine:libinit_plugin_engine"
"name": "//base/startup/init_lite/services/init/module_engine:libinit_module_engine"
}
],
"test": [
......
......@@ -144,6 +144,11 @@ if (defined(ohos_lite)) {
"fs_manager/fstab_mount.c",
]
modulemgr_sources = [
"hookmgr/hookmgr.c",
"modulemgr/modulemgr.c",
]
ohos_shared_library("libbegetutil") {
sources = [
"//base/startup/init_lite/services/log/init_log.c",
......@@ -157,6 +162,7 @@ if (defined(ohos_lite)) {
sources += fs_manager_sources
sources += syspara_sources
sources += [ "syspara/param_wrapper.cpp" ]
sources += modulemgr_sources
defines = [
"INIT_AGENT",
......
/*
* 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.
*/
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "list.h"
#include "hookmgr.h"
// Forward declaration
typedef struct tagHOOK_STAGE HOOK_STAGE;
/*
* Internal HOOK Item with priorities
*/
typedef struct tagHOOK_ITEM {
ListNode node;
int prio;
OhosHook hook;
HOOK_STAGE *stage;
} HOOK_ITEM;
/*
* Internal HOOK Stage in the same stage
*/
struct tagHOOK_STAGE {
ListNode node;
int stage;
ListNode hooks;
};
/*
* HookManager is consist of different hook stages
*/
struct tagHOOK_MGR {
const char *name;
ListNode stages;
};
/*
* Default HookManager is created automatically for HookMgrAddHook
*/
static HOOK_MGR *defaultHookMgr = NULL;
static HOOK_MGR *getHookMgr(HOOK_MGR *hookMgr, int autoCreate)
{
if (hookMgr != NULL) {
return hookMgr;
}
// Use default HOOK_MGR if possible
if (defaultHookMgr != NULL) {
return defaultHookMgr;
}
if (!autoCreate) {
return NULL;
}
// Create default HOOK_MGR if not created
defaultHookMgr = HookMgrCreate("default");
return defaultHookMgr;
}
static int hookStageCompare(ListNode *node, void *data)
{
const HOOK_STAGE *stage;
int compareStage = *((int *)data);
stage = (const HOOK_STAGE *)node;
return (stage->stage - compareStage);
}
static void hookStageDestroy(ListNode *node)
{
HOOK_STAGE *stage;
if (node == NULL) {
return;
}
stage = (HOOK_STAGE *)node;
ListRemoveAll(&(stage->hooks), NULL);
free((void *)stage);
}
// Get HOOK_STAGE if found, otherwise create it
static HOOK_STAGE *getHookStage(HOOK_MGR *hookMgr, int stage, int createIfNotFound)
{
HOOK_STAGE *stageItem;
stageItem = (HOOK_STAGE *)ListFind(&(hookMgr->stages), (void *)(&stage), hookStageCompare);
if (stageItem != NULL) {
return stageItem;
}
if (!createIfNotFound) {
return NULL;
}
// Not found, create it
stageItem = (HOOK_STAGE *)malloc(sizeof(HOOK_STAGE));
if (stageItem == NULL) {
return NULL;
}
stageItem->stage = stage;
ListInit(&(stageItem->hooks));
ListAddTail(&(hookMgr->stages), (ListNode *)stageItem);
return stageItem;
}
static int hookItemCompare(ListNode *node, ListNode *newNode)
{
const HOOK_ITEM *hookItem;
const HOOK_ITEM *newItem;
hookItem = (const HOOK_ITEM *)node;
newItem = (const HOOK_ITEM *)newNode;
return (hookItem->prio - newItem->prio);
}
struct HOOKITEM_COMPARE_VAL {
int prio;
OhosHook hook;
};
static int hookItemCompareValue(ListNode *node, void *data)
{
const HOOK_ITEM *hookItem;
struct HOOKITEM_COMPARE_VAL *compareVal = (struct HOOKITEM_COMPARE_VAL *)data;
hookItem = (const HOOK_ITEM *)node;
if (hookItem->prio != compareVal->prio) {
return (hookItem->prio - compareVal->prio);
}
if (hookItem->hook == compareVal->hook) {
return 0;
}
return -1;
}
// Add hook to stage list with prio ordered
static int addHookToStage(HOOK_STAGE *hookStage, int prio, OhosHook hook)
{
HOOK_ITEM *hookItem;
struct HOOKITEM_COMPARE_VAL compareVal;
// Check if exists
compareVal.prio = prio;
compareVal.hook = hook;
hookItem = (HOOK_ITEM *)ListFind(&(hookStage->hooks), (void *)(&compareVal), hookItemCompareValue);
if (hookItem != NULL) {
return 0;
}
// Create new item
hookItem = (HOOK_ITEM *)malloc(sizeof(HOOK_ITEM));
if (hookItem == NULL) {
return -1;
}
hookItem->prio = prio;
hookItem->hook = hook;
hookItem->stage = hookStage;
// Insert with order
ListAddWithOrder(&(hookStage->hooks), (ListNode *)hookItem, hookItemCompare);
return 0;
}
int HookMgrAdd(HOOK_MGR *hookMgr, int stage, int prio, OhosHook hook)
{
HOOK_STAGE *stageItem;
if (hook == NULL) {
return -1;
}
// Get HOOK_MGR
hookMgr = getHookMgr(hookMgr, true);
if (hookMgr == NULL) {
return -1;
}
// Get HOOK_STAGE list
stageItem = getHookStage(hookMgr, stage, true);
if (stageItem == NULL) {
return -1;
}
// Add hook to stage
return addHookToStage(stageItem, prio, hook);
}
static int hookTraversalDelProc(ListNode *node, void *cookie)
{
HOOK_ITEM *hookItem = (HOOK_ITEM *)node;
// Not equal, just return
if ((void *)hookItem->hook != cookie) {
return 0;
}
// Remove from the list
ListRemove(node);
// Destroy myself
free((void *)node);
return 0;
}
/*
* 删除钩子函数
* hook为NULL,表示删除该stage上的所有hooks
*/
void HookMgrDel(HOOK_MGR *hookMgr, int stage, OhosHook hook)
{
HOOK_STAGE *stageItem;
// Get HOOK_MGR
hookMgr = getHookMgr(hookMgr, 0);
if (hookMgr == NULL) {
return;
}
// Get HOOK_STAGE list
stageItem = getHookStage(hookMgr, stage, false);
if (stageItem == NULL) {
return;
}
if (hook != NULL) {
ListTraversal(&(stageItem->hooks), hook, hookTraversalDelProc, 0);
return;
}
// Remove from list
ListRemove((ListNode *)stageItem);
// Destroy stage item
hookStageDestroy((ListNode *)stageItem);
}
static int hookTraversalProc(ListNode *node, void *cookie)
{
HOOK_ITEM *hookItem = (HOOK_ITEM *)node;
HOOK_INFO hookInfo;
const HOOK_EXEC_ARGS *args = (const HOOK_EXEC_ARGS *)cookie;
hookInfo.stage = hookItem->stage->stage;
hookInfo.prio = hookItem->prio;
hookInfo.hook = hookItem->hook;
hookInfo.cookie = NULL;
hookInfo.retVal = 0;
if (args != NULL) {
hookInfo.cookie = args->cookie;
}
if ((args != NULL) && (args->preHook != NULL)) {
args->preHook(&hookInfo);
}
hookInfo.retVal = hookItem->hook(hookInfo.stage, hookItem->prio, args->cookie);
if ((args != NULL) && (args->postHook != NULL)) {
args->postHook(&hookInfo);
}
return hookInfo.retVal;
}
/*
* 执行钩子函数
*/
int HookMgrExecute(HOOK_MGR *hookMgr, int stage, const HOOK_EXEC_ARGS *args)
{
int flags;
HOOK_STAGE *stageItem;
// Get HOOK_MGR
hookMgr = getHookMgr(hookMgr, 0);
if (hookMgr == NULL) {
return -1;
}
// Get HOOK_STAGE list
stageItem = getHookStage(hookMgr, stage, false);
if (stageItem == NULL) {
return -1;
}
flags = 0;
if (args != NULL) {
flags = args->flags;
}
// Traversal all hooks in the specified stage
return ListTraversal(&(stageItem->hooks), (void *)args,
hookTraversalProc, flags);
}
HOOK_MGR *HookMgrCreate(const char *name)
{
HOOK_MGR *ret;
if (name == NULL) {
return NULL;
}
ret = (HOOK_MGR *)malloc(sizeof(HOOK_MGR));
if (ret == NULL) {
return NULL;
}
ret->name = strdup(name);
if (ret->name == NULL) {
free((void *)ret);
return NULL;
}
ListInit(&(ret->stages));
return ret;
}
void HookMgrDestroy(HOOK_MGR *hookMgr)
{
hookMgr = getHookMgr(hookMgr, 0);
if (hookMgr == NULL) {
return;
}
ListRemoveAll(&(hookMgr->stages), hookStageDestroy);
if (hookMgr == defaultHookMgr) {
defaultHookMgr = NULL;
}
if (hookMgr->name != NULL) {
free((void *)hookMgr->name);
}
free((void *)hookMgr);
}
typedef struct tagHOOK_TRAVERSAL_ARGS {
HOOK_INFO hookInfo;
OhosHookTraversal traversal;
} HOOK_TRAVERSAL_ARGS;
static int hookItemTraversal(ListNode *node, void *data)
{
HOOK_ITEM *hookItem;
HOOK_TRAVERSAL_ARGS *stageArgs;
hookItem = (HOOK_ITEM *)node;
stageArgs = (HOOK_TRAVERSAL_ARGS *)data;
stageArgs->hookInfo.prio = hookItem->prio;
stageArgs->hookInfo.hook = hookItem->hook;
stageArgs->traversal(&(stageArgs->hookInfo));
return 0;
}
static int hookStageTraversal(ListNode *node, void *data)
{
HOOK_STAGE *stageItem;
HOOK_TRAVERSAL_ARGS *stageArgs;
stageItem = (HOOK_STAGE *)node;
stageArgs = (HOOK_TRAVERSAL_ARGS *)data;
stageArgs->hookInfo.stage = stageItem->stage;
ListTraversal(&(stageItem->hooks), data, hookItemTraversal, 0);
return 0;
}
/*
* 遍历所有的hooks
*/
void HookMgrTraversal(HOOK_MGR *hookMgr, void *cookie, OhosHookTraversal traversal)
{
HOOK_TRAVERSAL_ARGS stageArgs;
if (traversal == NULL) {
return;
}
hookMgr = getHookMgr(hookMgr, 0);
if (hookMgr == NULL) {
return;
}
// Prepare common args
stageArgs.hookInfo.cookie = cookie;
stageArgs.hookInfo.retVal = 0;
stageArgs.traversal = traversal;
ListTraversal(&(hookMgr->stages), (void *)(&stageArgs), hookStageTraversal, 0);
}
/*
* 获取指定stage中hooks的个数
*/
int HookMgrGetHooksCnt(HOOK_MGR *hookMgr, int stage)
{
HOOK_STAGE *stageItem;
hookMgr = getHookMgr(hookMgr, 0);
if (hookMgr == NULL) {
return 0;
}
// Get HOOK_STAGE list
stageItem = getHookStage(hookMgr, stage, false);
if (stageItem == NULL) {
return 0;
}
return ListGetCnt(&(stageItem->hooks));
}
/*
* 获取指定stage中hooks的个数
*/
int HookMgrGetStagesCnt(HOOK_MGR *hookMgr)
{
hookMgr = getHookMgr(hookMgr, 0);
if (hookMgr == NULL) {
return 0;
}
return ListGetCnt(&(hookMgr->stages));
}
/*
* 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.
*/
#ifndef OHOS_HOOK_MANAGER_H__
#define OHOS_HOOK_MANAGER_H__
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif
/**
* @brief A Hook is a means of executing custom code (function) for existing running code.
*
* For a running process, it may consists of several stages.
* HookManager can help to add hooks to different stages with different priorities.
* The relationships for HookManager, HookStage and HookItem are shown as below:
*
* | ̄ ̄ ̄ ̄ ̄ ̄|
* | HookMgr |
* |__________|
* |
* | |▔▔▔▔▔▔▔▔▔▔▔| |▔▔▔▔▔▔▔▔▔▔▔|
* └--->| HookStage |--->| HookStage | ...
* |___________| |___________|
* |
* | |▔▔▔▔▔▔▔▔▔▔| |▔▔▔▔▔▔▔▔▔▔|
* └--->| HookItem |--->| HookItem | ...
* |__________| |__________|
*
* Usage example:
*
* For an existing module with several stages as below:
* ExistingStage1(...);
* ExistingStage2(...);
* ExistingStage3(...);
* We can add hooks capability to it as below:
* HookMgrExecute(hookMgr, PRE_STAGE1, ...);
* ExistingStage1(...);
* HookMgrExecute(hookMgr, PRE_STAGE2, ...);
* ExistingStage2(...);
* HookMgrExecute(hookMgr, PRE_STAGE3, ...);
* ExistingStage3(...);
* HookMgrExecute(hookMgr, POST_STAGE3, ...);
*
* For extending modules, we can add hooks without changing the existing module as below:
* int sampleHook() {
* ...
* }
* HookMgrAdd(hookMgr, PRE_STAGE1, priority, sampleHook);
*/
/* Forward declaration for HookManager */
typedef struct tagHOOK_MGR HOOK_MGR;
/**
* @brief Hook function prototype
*
* @param stage hook stage
* @param prio hook priority
* @param cookie input arguments for running the hook function
* @return return 0 if succeed; other values if failed.
*/
typedef int (*OhosHook)(int stage, int priority, void *cookie);
/**
* @brief Add a hook function
*
* @param hookMgr HookManager handle.
* If hookMgr is NULL, it will use default HookManager
* @param stage hook stage
* @param prio hook priority
* @param hook hook function pointer
* @return return 0 if succeed; other values if failed.
*/
int HookMgrAdd(HOOK_MGR *hookMgr, int stage, int prio, OhosHook hook);
/**
* @brief Delete hook function
*
* @param hookMgr HookManager handle.
* If hookMgr is NULL, it will use default HookManager
* @param stage hook stage
* @param hook hook function pointer
* If hook is NULL, it will delete all hooks in the stage
* @return None
*/
void HookMgrDel(HOOK_MGR *hookMgr, int stage, OhosHook hook);
/**
* @brief Hook information for executing or traversing hooks
*/
typedef struct tagHOOK_INFO {
int stage; /* hook stage */
int prio; /* hook priority */
OhosHook hook; /* hook function */
void *cookie; /* hook execution cookie */
int retVal; /* hook execution return value */
} HOOK_INFO;
/**
* @brief preHook and postHook function prototype for HookMgrExecute
*
* @param context HOOK_INFO for executing each hook.
* @return None
*/
typedef void (*OhosHookExecutionHook)(const HOOK_INFO *hookInfo);
/* Executing hooks in descending priority order */
#define HOOK_EXEC_REVERSE_ORDER 0x01
/* Stop executing hooks when error returned for each hook */
#define HOOK_EXEC_EXIT_WHEN_ERROR 0x02
/**
* @brief Extra execution arguments for HookMgrExecute
*/
typedef struct tagHOOK_EXEC_ARGS {
/* Executing flags */
int flags;
/* Executing cookie */
void *cookie;
/* preHook for before executing each hook */
OhosHookExecutionHook preHook;
/* postHook for before executing each hook */
OhosHookExecutionHook postHook;
} HOOK_EXEC_ARGS;
/**
* @brief Executing each hooks in specified stages
*
* @param hookMgr HookManager handle.
* If hookMgr is NULL, it will use default HookManager
* @param stage hook stage
* @param extraArgs HOOK_EXEC_ARGS for executing each hook.
* @return return 0 if succeed; other values if failed.
*/
int HookMgrExecute(HOOK_MGR *hookMgr, int stage, const HOOK_EXEC_ARGS *extraArgs);
/**
* @brief Create a HookManager handle
*
* @param name HookManager name.
* @return return HookManager handle; NULL if failed.
*/
HOOK_MGR *HookMgrCreate(const char *name);
/**
* @brief Destroy HookManager
*
* @param hookMgr HookManager handle.
* If hookMgr is NULL, it will use default HookManager
* @return None.
*/
void HookMgrDestroy(HOOK_MGR *hookMgr);
/**
* @brief Hook traversal function prototype
*
* @param hookInfo HOOK_INFO for traversing each hook.
* @return None
*/
typedef void (*OhosHookTraversal)(const HOOK_INFO *hookInfo);
/**
* @brief Traversing all hooks in the HookManager
*
* @param hookMgr HookManager handle.
* If hookMgr is NULL, it will use default HookManager
* @param cookie traversal cookie.
* @param traversal traversal function.
* @return None.
*/
void HookMgrTraversal(HOOK_MGR *hookMgr, void *cookie, OhosHookTraversal traversal);
/**
* @brief Get number of hooks in specified stage
*
* @param hookMgr HookManager handle.
* If hookMgr is NULL, it will use default HookManager
* @param stage hook stage.
* @return number of hooks, return 0 if none
*/
int HookMgrGetHooksCnt(HOOK_MGR *hookMgr, int stage);
/**
* @brief Get number of stages in the HookManager
*
* @param hookMgr HookManager handle.
* If hookMgr is NULL, it will use default HookManager
* @return number of stages, return 0 if none
*/
int HookMgrGetStagesCnt(HOOK_MGR *hookMgr);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
#endif
/*
* 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.
*/
#ifndef OHOS_MODULES_MANAGER_H__
#define OHOS_MODULES_MANAGER_H__
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif
/**
* @brief Module constructor function
*
* For static modules, this code is executed before main().
* For dynamic modules, this code is executed when ModuleMgrInstall().
*
* Usage example:
* MODULE_CONSTRUCTOR(void)
* {
* ...
* }
*/
#define MODULE_CONSTRUCTOR(void) static void _init(void) __attribute__((constructor)); static void _init(void)
/**
* @brief Module destructor function
*
* For static modules, this code will not be executed.
* For dynamic modules, this code is executed when ModuleMgrUninstall().
*
* Usage example:
* MODULE_DESTRUCTOR(void)
* {
* ...
* }
*/
#define MODULE_DESTRUCTOR(void) static void _destroy(void) __attribute__((destructor)); static void _destroy(void)
// Forward declaration
typedef struct tagMODULE_MGR MODULE_MGR;
/**
* @brief Create dynamic module manager
*
* This dynamic module manager will manager modules
* in the directory: /system/lib/{name}/
* @param name module manager name
* @return return module manager handle if succeed; return NULL if failed.
*/
MODULE_MGR *ModuleMgrCreate(const char *name);
/**
* @brief Destroy dynamic module manager
*
* It will uninstall all modules managed by this moduleMgr
* @param moduleMgr module manager handle
* @return None
*/
void ModuleMgrDestroy(MODULE_MGR *moduleMgr);
/**
* @brief Install a module
*
* The final module path is: /system/lib/{moduleMgrPath}/{moduleNmae}.z.so
*
* @param moduleMgr module manager handle
* @param moduleName module name
* @param argc argument counts for installing
* @param argv arguments for installing, the last argument is NULL.
* @return module handle returned by dlopen
*/
int ModuleMgrInstall(MODULE_MGR *moduleMgr, const char *moduleName,
int argc, const char *argv[]);
/**
* @brief Module install arguments
*/
typedef struct {
int argc;
const char **argv;
} MODULE_INSTALL_ARGS;
/**
* @brief Get module install arguments
*
* This function is available only in MODULE_CONSTRUCTOR.
*
* @return install args if succeed; return NULL if failed.
*/
const MODULE_INSTALL_ARGS *ModuleMgrGetArgs(void);
/**
* @brief Scan and install all modules in specified directory
*
* @param modulePath path for modules to be installed
* @return install args if succeed; return NULL if failed.
*/
MODULE_MGR *ModuleMgrScan(const char *modulePath);
/**
* @brief Uninstall module
*
* @param moduleMgr module manager handle
* @param name module name. If name is NULL, it will uninstall all modules.
* @return install args if succeed; return NULL if failed.
*/
void ModuleMgrUninstall(MODULE_MGR *moduleMgr, const char *name);
/**
* @brief Get number of modules in module manager
*
* @param hookMgr module manager handle
* @return number of modules, return 0 if none
*/
int ModuleMgrGetCnt(const MODULE_MGR *moduleMgr);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
#endif
/*
* 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.
*/
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <sys/types.h>
#include <dirent.h>
#include <linux/limits.h>
#include "list.h"
#include "securec.h"
#include "modulemgr.h"
#define MODULE_SUFFIX_D ".z.so"
struct tagMODULE_MGR {
ListNode modules;
const char *name;
MODULE_INSTALL_ARGS installArgs;
};
MODULE_MGR *ModuleMgrCreate(const char *name)
{
MODULE_MGR *moduleMgr;
if (name == NULL) {
return NULL;
}
moduleMgr = (MODULE_MGR *)malloc(sizeof(MODULE_MGR));
if (moduleMgr == NULL) {
return NULL;
}
ListInit(&(moduleMgr->modules));
moduleMgr->name = strdup(name);
if (moduleMgr->name == NULL) {
free((void *)moduleMgr);
return NULL;
}
moduleMgr->installArgs.argc = 0;
moduleMgr->installArgs.argv = NULL;
return moduleMgr;
}
void ModuleMgrDestroy(MODULE_MGR *moduleMgr)
{
if (moduleMgr == NULL) {
return;
}
ModuleMgrUninstall(moduleMgr, NULL);
if (moduleMgr->name != NULL) {
free((void *)moduleMgr->name);
}
free((void *)moduleMgr);
}
/*
* Module Item related api
*/
typedef struct tagMODULE_ITEM {
ListNode node;
MODULE_MGR *moduleMgr;
const char *name;
void *handle;
} MODULE_ITEM;
static void moduleDestroy(ListNode *node)
{
MODULE_ITEM *module;
if (node == NULL) {
return;
}
module = (MODULE_ITEM *)node;
if (module->name != NULL) {
free((void *)module->name);
}
if (module->handle != NULL) {
dlclose(module->handle);
}
free((void *)module);
}
static MODULE_INSTALL_ARGS *currentInstallArgs = NULL;
static void *moduleInstall(MODULE_ITEM *module, int argc, const char *argv[])
{
void *handle;
char path[PATH_MAX];
module->moduleMgr->installArgs.argc = argc;
module->moduleMgr->installArgs.argv = argv;
if (module->moduleMgr->name[0] == '/') {
snprintf_s(path, sizeof(path), sizeof(path) - 1, "%s/%s" MODULE_SUFFIX_D, module->moduleMgr->name, module->name);
} else {
snprintf_s(path, sizeof(path), sizeof(path) - 1, "/system/lib/%s/%s" MODULE_SUFFIX_D, module->moduleMgr->name, module->name);
}
currentInstallArgs = &(module->moduleMgr->installArgs);
handle = dlopen(path, RTLD_LAZY | RTLD_GLOBAL);
currentInstallArgs = NULL;
return handle;
}
/*
* 用于扫描安装指定目录下所有的插件。
*/
int ModuleMgrInstall(MODULE_MGR *moduleMgr, const char *moduleName,
int argc, const char *argv[])
{
MODULE_ITEM *module;
// Get module manager
if ((moduleMgr == NULL) || (moduleName == NULL)) {
return -1;
}
// Create module item
module = (MODULE_ITEM *)malloc(sizeof(MODULE_ITEM));
if (module == NULL) {
return -1;
}
module->handle = NULL;
module->moduleMgr = moduleMgr;
module->name = strdup(moduleName);
if (module->name == NULL) {
moduleDestroy((ListNode *)module);
return -1;
}
// Install
module->handle = moduleInstall(module, argc, argv);
if (module->handle == NULL) {
moduleDestroy((ListNode *)module);
return -1;
}
// Add to list
ListAddTail(&(moduleMgr->modules), (ListNode *)module);
return 0;
}
const MODULE_INSTALL_ARGS *ModuleMgrGetArgs(void)
{
return currentInstallArgs;
}
static int stringEndsWith(const char *srcStr, const char *endStr)
{
int srcStrLen = strlen(srcStr);
int endStrLen = strlen(endStr);
if (srcStrLen < endStrLen) {
return -1;
}
srcStr += (srcStrLen - endStrLen);
if (strcmp(srcStr, endStr) == 0) {
return (srcStrLen - endStrLen);
}
return -1;
}
static void scanModules(MODULE_MGR *moduleMgr, const char *path)
{
int end;
int ret;
DIR *dir;
struct dirent *file;
dir = opendir(path);
if (dir == NULL) {
return;
}
while (1) {
file = readdir(dir);
if (file == NULL) {
break;
}
if ((file->d_type != DT_REG) && (file->d_type != DT_LNK)) {
continue;
}
// Must be ended with MODULE_SUFFIX_D
end = stringEndsWith(file->d_name, MODULE_SUFFIX_D);
if (end <= 0) {
continue;
}
file->d_name[end] = '\0';
ret = ModuleMgrInstall(moduleMgr, file->d_name, 0, NULL);
}
closedir(dir);
}
/*
* 用于扫描安装指定目录下所有的插件。
*/
MODULE_MGR *ModuleMgrScan(const char *modulePath)
{
MODULE_MGR *moduleMgr;
char path[PATH_MAX];
moduleMgr = ModuleMgrCreate(modulePath);
if (moduleMgr == NULL) {
return NULL;
}
if (modulePath[0] == '/') {
snprintf_s(path, sizeof(path), sizeof(path) - 1, "%s", modulePath);
} else {
snprintf_s(path, sizeof(path), sizeof(path) - 1, "/system/lib/%s", modulePath);
}
scanModules(moduleMgr, path);
return moduleMgr;
}
static int moduleCompare(ListNode *node, void *data)
{
MODULE_ITEM *module = (MODULE_ITEM *)node;
return strcmp(module->name, (char *)data);
}
/*
* 卸载指定插件。
*/
void ModuleMgrUninstall(MODULE_MGR *moduleMgr, const char *name)
{
MODULE_ITEM *module;
if (moduleMgr == NULL) {
return;
}
// Uninstall all modules if no name specified
if (name == NULL) {
ListRemoveAll(&(moduleMgr->modules), moduleDestroy);
return;
}
// Find module by name
module = (MODULE_ITEM *)ListFind(&(moduleMgr->modules), (void *)name, moduleCompare);
if (module == NULL) {
return;
}
// Remove from the list
ListRemove((ListNode *)module);
// Destroy the module
moduleDestroy((ListNode *)module);
}
int ModuleMgrGetCnt(const MODULE_MGR *moduleMgr)
{
if (moduleMgr == NULL) {
return 0;
}
return ListGetCnt(&(moduleMgr->modules));
}
......@@ -150,16 +150,23 @@ if (defined(ohos_lite)) {
"init/standard/device.c",
"init/standard/fd_holder_service.c",
"init/standard/init.c",
"init/standard/init_cmdexecutor.c",
"init/standard/init_cmds.c",
"init/standard/init_jobs.c",
"init/standard/init_mount.c",
"init/standard/init_plugin_manager.c",
"init/standard/init_reboot.c",
"init/standard/init_service.c",
"init/standard/init_signal_handler.c",
"init/standard/switch_root.c",
]
modulemgr_sources = [
"//base/startup/init_lite/interfaces/innerkits/hookmgr/hookmgr.c",
"//base/startup/init_lite/interfaces/innerkits/modulemgr/modulemgr.c",
"init/module_engine/init_modulemgr.c",
]
sources += modulemgr_sources
sources += init_common_sources
include_dirs = [
......@@ -170,6 +177,7 @@ if (defined(ohos_lite)) {
"//base/startup/init_lite/services/include/param",
"//base/startup/init_lite/services/include",
"//base/startup/init_lite/services/init/include",
"//base/startup/init_lite/services/init/module_engine/include",
"//base/startup/init_lite/services/log",
"//base/startup/init_lite/interfaces/innerkits/include",
"//base/startup/init_lite/services/loopevent/include",
......@@ -195,7 +203,9 @@ if (defined(ohos_lite)) {
"//third_party/cJSON:cjson_static",
]
deps += [ "//base/startup/init_lite/services/init/plugin_engine:libinit_stub_versionscript" ]
deps += [ "//base/startup/init_lite/services/init/module_engine:libinit_stub_versionscript" ]
deps += [ "//base/startup/init_lite/services/modules:static_modules" ]
cflags = []
......@@ -238,9 +248,9 @@ if (defined(ohos_lite)) {
defines += [ "PRODUCT_RK" ]
}
version_script = get_label_info(
"//base/startup/init_lite/services/init/plugin_engine:libinit_stub_versionscript",
"//base/startup/init_lite/services/init/module_engine:libinit_stub_versionscript",
"target_gen_dir") + "/" + get_label_info(
"//base/startup/init_lite/services/init/plugin_engine:libinit_stub_versionscript",
"//base/startup/init_lite/services/init/module_engine:libinit_stub_versionscript",
"name") + stub_version_script_suffix
defines += [ "_GNU_SOURCE" ]
install_images = [
......@@ -376,11 +386,6 @@ if (defined(ohos_lite)) {
part_name = "init"
}
ohos_prebuilt_etc("plugin_modules") {
source = "//base/startup/init_lite/services/etc/plugin_modules.cfg"
part_name = "init"
}
ohos_prebuilt_etc("system-sandbox.json") {
if (target_cpu == "arm64") {
source = "//base/startup/init_lite/interfaces/innerkits/sandbox/system-sandbox64.json"
......@@ -451,7 +456,6 @@ if (defined(ohos_lite)) {
":ohos.para.dac",
":ohos_const.para",
":passwd",
":plugin_modules",
":privapp-sandbox.json",
":syscap.json",
":syscap.para",
......
......@@ -94,7 +94,7 @@ if (defined(ohos_lite)) {
if (param_test) {
sources +=
[ "//base/startup/init_lite/test/plugintest/plugin_param_cmd.c" ]
[ "//base/startup/init_lite/test/moduletest/param_test_cmds.c" ]
deps += [
"//base/startup/init_lite/interfaces/innerkits:libbeget_proxy",
"//base/startup/init_lite/services/loopevent:loopevent",
......@@ -171,7 +171,7 @@ if (defined(ohos_lite)) {
if (param_test) {
sources +=
[ "//base/startup/init_lite/test/plugintest/plugin_param_cmd.c" ]
[ "//base/startup/init_lite/test/moduletest/param_test_cmds.c" ]
deps += [
"//base/startup/init_lite/interfaces/innerkits:libbeget_proxy",
"//base/startup/init_lite/services/loopevent:loopevent",
......
{
"modules" : [
{
"name": "bootchart",
"start-mode" : "static",
"lib-name" : "libbootchart.z.so"
}
]
}
\ No newline at end of file
文件模式从 100644 更改为 100755
......@@ -23,6 +23,24 @@ extern "C" {
#endif
#endif
/**
* @brief Double linked list structure is show as below:
*
* | ̄ ̄ ̄ ̄ ̄|-----------------------------------------------|
* |->| head | |
* | |________|<-------------------------------------------| |
* | | | |
* | └-next->|▔▔▔▔▔▔|-next->|▔▔▔▔▔▔|-next->|▔▔▔▔▔▔|-next--| |
* └------prev-| node |<-prev-| node |<-prev-| node |<-prev----|
* |------| |------| |------|
* | extra| | extra| | extra|
* |______| |______| |______|
*
*/
/**
* @brief Double linked list node
*/
typedef struct ListNode {
struct ListNode *next;
struct ListNode *prev;
......@@ -32,9 +50,125 @@ typedef struct ListNode {
#define ListEntry(ptr, type, member) ((type *)((char *)(ptr) - offsetof(type, member)))
#define ForEachListEntry(list, node) for (node = (list)->next; node != (list); node = node->next)
/**
* @brief Initialize a double-linked list head
*
* All other list API should be initialized by this function.\n
*
* @param head list head, make sure head is valid pointer
* @return None
*/
void ListInit(struct ListNode *list);
/**
* @brief Add a node to the end of the list
*
* @param head list head, make sure head is valid pointer
* @param item new node to be added
* @return None
*/
void ListAddTail(struct ListNode *list, struct ListNode *item);
/**
* @brief Remove a node from the list
*
* @param item the node to be removed from the list.
* This function does not free any memory within item.
* @return None
*/
void ListRemove(struct ListNode *item);
/**
* @brief ListNode comparision function prototype
*
* @param node ListNode to be compared.
* @param newNode new ListNode to be compared.
* @return
* <0 if node < newNode
* =0 if node = newNode
* >0 if Node > newNode
*/
typedef int (*ListCompareProc)(ListNode *node, ListNode *newNode);
/**
* @brief Add a node to the list with order
*
* @param head list head, make sure head is valid pointer
* @param item new node to be added
* @param compareProc comparison function for adding node
* if it is ascending order, this function should return an integer less than,
* equal to, or greater than zero if the first argument is considered to be
* respectively less than, equal to, or greater than the second.
* @return None
*/
void ListAddWithOrder(struct ListNode *head, struct ListNode *item, ListCompareProc compareProc);
/**
* @brief ListNode traversing and find function prototype
*
* @param node ListNode to be compared.
* @param data value for traversing
* @return
* return 0 if node value equals data for ListFind
*/
typedef int (*ListTraversalProc)(ListNode *node, void *data);
/**
* @brief Find a node by traversing the list
*
* @param head list head, make sure head is valid pointer.
* @param data comparing data.
* @param compareProc comparing function, return 0 if matched.
* @return the found node; return NULL if none is found.
*/
ListNode *ListFind(const ListNode *head, void *data, ListTraversalProc compareProc);
/* Traversing from end to start */
#define TRAVERSE_REVERSE_ORDER 0x1
/* Stop traversing when error returned */
#define TRAVERSE_STOP_WHEN_ERROR 0x2
/**
* @brief Traversal the list with specified function
*
* @param head list head, make sure head is valid pointer.
* @param cookie optinal traversing data.
* @param traversalProc comparing function, return 0 if matched.
* @param flags optinal traversing flags:
* TRAVERSE_REVERSE_ORDER: traversing from last node to first node;
* default behaviour is from first node to last node
* TRAVERSE_STOP_WHEN_ERROR: stop traversing if traversalProc return non-zero
* default behaviour will ignore traversalProc return values
* @return return -1 for invalid input arguments.
* when TRAVERSE_STOP_WHEN_ERROR is specified, it will return errors from traversalProc
*/
int ListTraversal(ListNode *head, void *data, ListTraversalProc traversalProc, int flags);
/**
* @brief ListNode destroy function prototype
*
* @param node ListNode to be destroyed.
* @return None
*/
typedef void (*ListDestroyProc)(ListNode *node);
/**
* @brief Find a node by traversing the list
*
* @param head list head, make sure head is valid pointer.
* @param destroyProc destroy function; if NULL, it will free each node by default.
* @return None
*/
void ListRemoveAll(ListNode *head, ListDestroyProc destroyProc);
/**
* @brief Get list count
*
* @param head list head, make sure head is valid pointer.
* @return the count of nodes in the list; return 0 if error
*/
int ListGetCnt(const ListNode *head);
#ifdef __cplusplus
#if __cplusplus
}
......
../module_engine/include/init_cmdexecutor.h
\ No newline at end of file
......@@ -18,7 +18,7 @@
#include <string.h>
#include "init_service.h"
#include "init_hashmap.h"
#include "init_plugin_manager.h"
#include "init_cmdexecutor.h"
#ifdef __cplusplus
#if __cplusplus
......@@ -55,7 +55,6 @@ typedef struct InitGroupNode_ {
unsigned char type;
union {
Service *service;
PluginInfo *pluginInfo;
PluginCmd *cmd;
} data;
char name[0];
......
......@@ -33,7 +33,7 @@
#include "init.h"
#include "init_jobs_internal.h"
#include "init_log.h"
#include "init_plugin_manager.h"
#include "init_cmdexecutor.h"
#include "init_service_manager.h"
#include "init_utils.h"
#ifdef WITH_SELINUX
......
......@@ -14,14 +14,17 @@
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" ]
config("libinit_module_engine_config") {
include_dirs = [
"//base/startup/init_lite/services/init/module_engine/include",
"//base/startup/init_lite/services/include",
"//base/startup/init_lite/interfaces/innerkits/include",
]
}
ohos_native_stub_library("libinit_plugin_engine") {
ohos_native_stub_library("libinit_module_engine") {
output_extension = "so"
public_configs = [ ":libinit_plugin_engine_config" ]
public_configs = [ ":libinit_module_engine_config" ]
stub_description_file = "./stub/libinit.stub.json"
}
......@@ -34,5 +37,5 @@ ohos_native_stub_library("libinit_stub_empty") {
stub_description_file = "./stub/libinit.stub.empty.json"
part_name = "init"
install_enable = true
symlink_target_name = [ "libinit_plugin_engine.so" ]
symlink_target_name = [ "libinit_module_engine.so" ]
}
/*
* 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.
*/
#ifndef BASE_STARTUP_BOOTSTAGE_H
#define BASE_STARTUP_BOOTSTAGE_H
#include "hookmgr.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif
enum INIT_BOOTSTAGE {
INIT_GLOBAL_INIT = 0,
INIT_PRE_PARAM_SERVICE = 10,
INIT_PRE_PARAM_LOAD = 20,
INIT_PRE_CFG_LOAD = 30,
INIT_POST_CFG_LOAD = 40
};
inline int InitAddGlobalInitHook(int prio, OhosHook hook)
{
return HookMgrAdd(NULL, INIT_GLOBAL_INIT, prio, hook);
}
inline int InitAddPreParamServiceHook(int prio, OhosHook hook)
{
return HookMgrAdd(NULL, INIT_PRE_PARAM_SERVICE, prio, hook);
}
inline int InitAddPreParamLoadHook(int prio, OhosHook hook)
{
return HookMgrAdd(NULL, INIT_PRE_PARAM_LOAD, prio, hook);
}
inline int InitAddPreCfgLoadHook(int prio, OhosHook hook)
{
return HookMgrAdd(NULL, INIT_PRE_CFG_LOAD, prio, hook);
}
inline int InitAddPostCfgLoadHook(int prio, OhosHook hook)
{
return HookMgrAdd(NULL, INIT_POST_CFG_LOAD, prio, hook);
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
#endif
......@@ -12,8 +12,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef STARTUP_INIT_PULUGIN_MANAGER_H
#define STARTUP_INIT_PULUGIN_MANAGER_H
#ifndef STARTUP_INIT_CMD_EXECUTOR_H
#define STARTUP_INIT_CMD_EXECUTOR_H
#include <stdlib.h>
#include <string.h>
......@@ -24,27 +24,6 @@
extern "C" {
#endif
#endif
#ifdef __aarch64__
#define DEFAULT_PLUGIN_PATH "/system/lib64/plugin"
#else
#define DEFAULT_PLUGIN_PATH "/system/lib/plugin"
#endif
#define DEFAULT_PLUGIN_CFG "/system/etc/plugin_modules.cfg"
typedef enum {
PLUGIN_STATE_IDLE,
PLUGIN_STATE_INIT,
PLUGIN_STATE_RUNNING,
PLUGIN_STATE_DESTORYED
} PluginState;
typedef struct PluginInfo_ {
int state;
int startMode;
int (*pluginInit)();
void (*pluginExit)();
char *name;
char *libName;
} PluginInfo;
typedef struct {
ListNode cmdExecutor;
......@@ -64,17 +43,11 @@ void PluginExecCmdByCmdIndex(int index, const char *cmdContent);
int PluginExecCmd(const char *name, int argc, const char **argv);
const char *PluginGetCmdIndex(const char *cmdStr, int *index);
int PluginUninstall(const char *name);
int PluginInstall(const char *name, const char *libName);
void PluginManagerInit(void);
int AddCmdExecutor(const char *cmdName, CmdExecutor execCmd);
int ParseInitCfg(const char *configFile, void *context);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
#endif // STARTUP_INIT_PULUGIN_MANAGER_H
#endif
......@@ -17,15 +17,17 @@
#define BASE_STARTUP_INIT_PLUGIN_H
#include <stdint.h>
#include <stdio.h>
#include "modulemgr.h"
#include "bootstage.h"
#include "init_modulemgr.h"
#include "init_cmdexecutor.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif
#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)
int SystemWriteParam(const char *name, const char *value);
int SystemReadParam(const char *name, char *value, unsigned int *len);
......@@ -36,8 +38,6 @@ 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));
#ifdef __cplusplus
#if __cplusplus
}
......
/*
* 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.
*/
#ifndef BASE_STARTUP_INIT_MODULEMGR_H
#define BASE_STARTUP_INIT_MODULEMGR_H
#include "modulemgr.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif
int InitModuleMgrInstall(const char *moduleName);
void InitModuleMgrUnInstall(const char *moduleName);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
#endif
/*
* Copyright (c) 2020-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.
*/
#include <stdlib.h>
#include "init_log.h"
#include "init_module_engine.h"
static MODULE_MGR *defaultModuleMgr = NULL;
int InitModuleMgrInstall(const char *moduleName)
{
if (moduleName == NULL) {
return -1;
}
if (defaultModuleMgr == NULL) {
defaultModuleMgr = ModuleMgrCreate(moduleName);
}
if (defaultModuleMgr == NULL) {
return -1;
}
return ModuleMgrInstall(defaultModuleMgr, moduleName, 0, NULL);
}
void InitModuleMgrUnInstall(const char *moduleName)
{
ModuleMgrUninstall(defaultModuleMgr, moduleName);
}
static int ModuleMgrCmdInstall(int id, const char *name, int argc, const char **argv)
{
INIT_ERROR_CHECK(argv != NULL && argc >= 1, return -1, "Invalid install parameter");
int ret;
ret = ModuleMgrInstall(NULL, argv[0], argc-1, argv+1);
INIT_ERROR_CHECK(ret == 0, return ret, "Install module %s fail", argv[0]);
return 0;
}
static int ModuleMgrCmdUninstall(int id, const char *name, int argc, const char **argv)
{
INIT_ERROR_CHECK(argv != NULL && argc >= 1, return -1, "Invalid install parameter");
ModuleMgrUninstall(NULL, argv[0]);
return 0;
}
static int moduleMgrCommandsInit(int stage, int prio, void *cookie)
{
// "ohos.servicectrl.install"
(void)AddCmdExecutor("install", ModuleMgrCmdInstall);
(void)AddCmdExecutor("uninstall", ModuleMgrCmdUninstall);
// read cfg and start static plugin
return 0;
}
MODULE_CONSTRUCTOR(void)
{
// Depends on parameter service
InitAddPreCfgLoadHook(0, moduleMgrCommandsInit);
}
......@@ -3,5 +3,11 @@
{ "name": "SystemReadParam" },
{ "name": "AddCmdExecutor" },
{ "name": "RemoveCmdExecutor" },
{ "name": "PluginRegister" }
{ "name": "InitAddGlobalInitHook" },
{ "name": "InitAddPreParamServiceHook" },
{ "name": "InitAddPreParamLoadHook" },
{ "name": "InitAddPreCfgLoadHook" },
{ "name": "InitAddPostCfgLoadHook" },
{ "name": "InitModuleMgrInstall" },
{ "name": "InitModuleMgrUnInstall" }
]
......@@ -18,6 +18,7 @@
#include <poll.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include <sys/sysmacros.h>
#include <sys/stat.h>
#include <sys/types.h>
......@@ -46,6 +47,7 @@
#include <policycoreutils.h>
#include <selinux/selinux.h>
#endif // WITH_SELINUX
#include "bootstage.h"
static bool g_enableSandbox;
......@@ -298,22 +300,66 @@ static void InitLoadParamFiles(void)
FreeCfgFiles(files);
}
typedef struct HOOK_TIMING_STAT {
struct timespec startTime;
struct timespec endTime;
} HOOK_TIMING_STAT;
static void InitPreHook(const HOOK_INFO *hookInfo)
{
HOOK_TIMING_STAT *stat = (HOOK_TIMING_STAT *)hookInfo->cookie;
clock_gettime(CLOCK_MONOTONIC, &(stat->startTime));
}
static void InitPostHook(const HOOK_INFO *hookInfo)
{
long long diff;
HOOK_TIMING_STAT *stat = (HOOK_TIMING_STAT *)hookInfo->cookie;
clock_gettime(CLOCK_MONOTONIC, &(stat->endTime));
diff = (long long)((stat->endTime.tv_sec - stat->startTime.tv_sec) / 1000);
if (stat->endTime.tv_nsec > stat->startTime.tv_nsec) {
diff += (stat->endTime.tv_nsec - stat->startTime.tv_nsec) * 1000;
} else {
diff -= (stat->endTime.tv_nsec - stat->startTime.tv_nsec) * 1000;
}
INIT_LOGI("Executing hook [%d:%d:%p] cost [%lld]ms, return %d.",
hookInfo->stage, hookInfo->prio, hookInfo->hook, diff, hookInfo->retVal);
}
void SystemConfig(void)
{
HOOK_TIMING_STAT timingStat;
HOOK_EXEC_ARGS args;
args.flags = 0;
args.cookie = (void *)&timingStat;
args.preHook = InitPreHook;
args.postHook = InitPostHook;
HookMgrExecute(NULL, INIT_GLOBAL_INIT, (void *)&args);
InitServiceSpace();
HookMgrExecute(NULL, INIT_PRE_PARAM_SERVICE, (void *)&args);
InitParamService();
InitParseGroupCfg();
PluginManagerInit();
RegisterBootStateChange(BootStateChange);
// load SELinux context and policy
// Do not move position!
SystemLoadSelinux();
// parse parameters
HookMgrExecute(NULL, INIT_PRE_PARAM_LOAD, (void *)&args);
InitLoadParamFiles();
// read config
HookMgrExecute(NULL, INIT_PRE_CFG_LOAD, (void *)&args);
ReadConfig();
INIT_LOGI("Parse init config file done.");
HookMgrExecute(NULL, INIT_POST_CFG_LOAD, (void *)&args);
// Destroy all hooks
HookMgrDestroy(NULL);
// dump config
#if defined(OHOS_SERVICE_DUMP)
......
......@@ -12,9 +12,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "init_plugin_manager.h"
#include <dlfcn.h>
#include "cJSON.h"
#include "init_param.h"
......@@ -23,6 +20,8 @@
#include "init_group_manager.h"
#include "init_service_manager.h"
#include "securec.h"
#include "modulemgr.h"
#include "init_module_engine.h"
#define MAX_CMD_ARGC 10
static int g_cmdExecutorId = 0;
......@@ -190,179 +189,3 @@ const char *PluginGetCmdIndex(const char *cmdStr, int *index)
INIT_LOGI("PluginGetCmdIndex content: %s index %d", cmd->name, *index);
return cmd->name;
}
static int LoadModule(const char *name, const char *libName)
{
char path[128] = {0}; // 128 path for plugin
int ret = 0;
if (libName == NULL) {
ret = sprintf_s(path, sizeof(path), "%s/lib%s.z.so", DEFAULT_PLUGIN_PATH, name);
} else {
ret = sprintf_s(path, sizeof(path), "%s/%s", DEFAULT_PLUGIN_PATH, libName);
}
INIT_ERROR_CHECK(ret > 0, return -1, "Failed to sprintf path %s", name);
char *realPath = GetRealPath(path);
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;
}
free(realPath);
dlclose(handle);
return 0;
}
int PluginInstall(const char *name, const char *libName)
{
// load so, and init module
int ret = LoadModule(name, libName);
INIT_ERROR_CHECK(ret == 0, return -1, "pluginInit is null %s", name);
PluginInfo *info = NULL;
InitGroupNode *groupNode = GetGroupNode(NODE_TYPE_PLUGINS, name);
if (groupNode != NULL && groupNode->data.pluginInfo != NULL) {
info = groupNode->data.pluginInfo;
}
INIT_ERROR_CHECK(info != NULL, return -1, "Failed to pluginInit %s", name);
INIT_LOGI("PluginInstall %s %d", name, info->state);
if (info->state == PLUGIN_STATE_INIT) {
INIT_ERROR_CHECK(info->pluginInit != NULL, return -1, "pluginInit is null %s", name);
ret = info->pluginInit();
INIT_ERROR_CHECK(ret == 0, return -1, "Failed to pluginInit %s", name);
info->state = PLUGIN_STATE_RUNNING;
}
return 0;
}
int PluginUninstall(const char *name)
{
InitGroupNode *groupNode = GetGroupNode(NODE_TYPE_PLUGINS, name);
INIT_ERROR_CHECK(groupNode != NULL && groupNode->data.pluginInfo != NULL,
return 0, "Can not find plugin %s", name);
PluginInfo *info = groupNode->data.pluginInfo;
INIT_ERROR_CHECK(info != NULL, return -1, "Failed to pluginInit %s", name);
INIT_LOGI("PluginUninstall %s %d %p", name, info->state, info->pluginInit);
if (info->state == PLUGIN_STATE_RUNNING) {
INIT_ERROR_CHECK(info->pluginExit != NULL, return -1, "pluginExit is null %s", name);
info->pluginExit();
info->state = PLUGIN_STATE_INIT;
}
return 0;
}
static PluginInfo *GetPluginInfo(const char *name)
{
InitGroupNode *groupNode = GetGroupNode(NODE_TYPE_PLUGINS, name);
if (groupNode == NULL) {
groupNode = AddGroupNode(NODE_TYPE_PLUGINS, name);
INIT_ERROR_CHECK(groupNode != NULL, return NULL, "Failed to create group node");
}
PluginInfo *info = groupNode->data.pluginInfo;
if (info == NULL) {
info = (PluginInfo *)calloc(1, sizeof(PluginInfo));
INIT_ERROR_CHECK(info != NULL, return NULL, "Failed to create module");
groupNode->data.pluginInfo = info;
info->name = groupNode->name;
info->state = 0;
info->startMode = 0;
info->libName = NULL;
}
return info;
}
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");
INIT_ERROR_CHECK(pluginInit != NULL && pluginExit != NULL,
return -1, "Invalid plugin constructor %s", name);
InitServiceSpace();
PluginInfo *info = GetPluginInfo(name);
INIT_ERROR_CHECK(info != NULL, return -1, "Failed to create group node");
info->state = PLUGIN_STATE_INIT;
info->pluginInit = pluginInit;
info->pluginExit = pluginExit;
// load config
if (config != NULL) {
ParseInitCfg(config, NULL);
}
return 0;
}
static int PluginCmdInstall(int id, const char *name, int argc, const char **argv)
{
INIT_ERROR_CHECK(argv != NULL && argc >= 1, return -1, "Invalid install parameter");
PluginInfo *info = GetPluginInfo(argv[0]);
int ret = 0;
if (info == NULL) {
ret = PluginInstall(argv[0], NULL);
} else {
ret = PluginInstall(argv[0], info->libName);
}
INIT_ERROR_CHECK(ret == 0, return ret, "Install plugin %s fail", argv[0]);
return 0;
}
static int PluginCmdUninstall(int id, const char *name, int argc, const char **argv)
{
INIT_ERROR_CHECK(argv != NULL && argc >= 1, return -1, "Invalid install parameter");
int ret = PluginUninstall(argv[0]);
INIT_ERROR_CHECK(ret == 0, return ret, "Uninstall plugin %s fail", argv[0]);
return 0;
}
static int LoadPluginCfg(void)
{
char *fileBuf = ReadFileToBuf(DEFAULT_PLUGIN_CFG);
INIT_ERROR_CHECK(fileBuf != NULL, return -1, "Failed to read file content %s", DEFAULT_PLUGIN_CFG);
cJSON *root = cJSON_Parse(fileBuf);
INIT_ERROR_CHECK(root != NULL, free(fileBuf);
return -1, "Failed to parse json file %s", DEFAULT_PLUGIN_CFG);
int itemNumber = 0;
cJSON *json = GetArrayItem(root, &itemNumber, "modules");
if (json == NULL) {
free(fileBuf);
return 0;
}
for (int i = 0; i < itemNumber; ++i) {
cJSON *item = cJSON_GetArrayItem(json, i);
char *moduleName = cJSON_GetStringValue(cJSON_GetObjectItem(item, "name"));
if (moduleName == NULL) {
INIT_LOGE("Failed to get plugin info");
continue;
}
PluginInfo *info = GetPluginInfo(moduleName);
if (info == NULL) {
INIT_LOGE("Failed to get plugin for module %s", moduleName);
continue;
}
info->startMode = 0;
char *mode = cJSON_GetStringValue(cJSON_GetObjectItem(item, "start-mode"));
if (mode == NULL || (strcmp(mode, "static") != 0)) {
info->startMode = 1;
}
char *libName = cJSON_GetStringValue(cJSON_GetObjectItem(item, "lib-name"));
if (libName != NULL) {
info->libName = strdup(libName); // do not care error
}
INIT_LOGI("LoadPluginCfg module %s %d libName %s", moduleName, info->startMode, info->libName);
if (info->startMode == 0) {
PluginInstall(moduleName, info->libName);
}
}
free(fileBuf);
return 0;
}
void PluginManagerInit(void)
{
// "ohos.servicectrl.install"
(void)AddCmdExecutor("install", PluginCmdInstall);
(void)AddCmdExecutor("uninstall", PluginCmdUninstall);
// read cfg and start static plugin
LoadPluginCfg();
}
......@@ -14,14 +14,14 @@
import("//base/startup/init_lite/begetd.gni")
import("//build/ohos.gni")
ohos_shared_library("libbootchart") {
ohos_shared_library("bootchart") {
sources = [ "bootchart/bootchart.c" ]
include_dirs = [
"//base/startup/init_lite/services/include",
"//base/startup/init_lite/services/include/param",
"//base/startup/init_lite/services/log",
"//base/startup/init_lite/services/plugin",
"//base/startup/init_lite/services/modules",
"//base/startup/init_lite/interfaces/innerkits/include",
"//third_party/bounds_checking_function/include",
]
......@@ -33,16 +33,31 @@ ohos_shared_library("libbootchart") {
"//third_party/cJSON:cjson_static",
]
external_deps = [ "init:libinit_plugin_engine" ]
external_deps = [ "init:libinit_module_engine" ]
part_name = "init"
if (target_cpu == "arm64") {
module_install_dir = "lib64/plugin"
} else {
module_install_dir = "lib/plugin"
}
module_install_dir = "lib/init"
}
group("plugin") {
deps = [ ":libbootchart" ]
config("libbootchart_static_config") {
include_dirs = [
"//base/startup/init_lite/services/log",
"//base/startup/init_lite/services/modules",
"//base/startup/init_lite/services/init/module_engine/include",
"//base/startup/init_lite/services/include",
"//base/startup/init_lite/interfaces/innerkits/include",
]
}
ohos_source_set("libbootchart_static") {
sources = [ "bootchart/bootchart_static.c" ]
public_configs = [ ":libbootchart_static_config" ]
}
group("modules") {
deps = [ ":bootchart" ]
}
group("static_modules") {
deps = [ ":libbootchart_static" ]
}
......@@ -22,7 +22,7 @@
#include <time.h>
#include <unistd.h>
#include "init_plugin_engine.h"
#include "init_module_engine.h"
#include "init_param.h"
#include "init_utils.h"
#include "plugin_adapter.h"
......@@ -219,13 +219,6 @@ static void BootchartDestory(void)
static int DoBootchartStart(void)
{
char enable[4] = {}; // 4 enable size
uint32_t size = sizeof(enable);
SystemReadParam("persist.init.bootchart.enabled", enable, &size);
if (strcmp(enable, "1") != 0) {
PLUGIN_LOGI("Not bootcharting");
return 0;
}
mkdir("/data/bootchart", S_IRWXU | S_IRWXG | S_IRWXO);
if (g_bootchartCtrl != NULL) {
PLUGIN_LOGI("bootcharting has been start");
......@@ -271,41 +264,14 @@ static int DoBootchartStop(void)
return 0;
}
static int DoBootchartCmd(int id, const char *name, int argc, const char **argv)
{
PLUGIN_LOGI("DoBootchartCmd argc %d %s", argc, name);
PLUGIN_CHECK(argc >= 1, return -1, "Invalid parameter");
if (strcmp(argv[0], "start") == 0) {
return DoBootchartStart();
} else if (strcmp(argv[0], "stop") == 0) {
return DoBootchartStop();
}
return 0;
}
static PluginCmd g_bootchartCmds[] = {
{"bootchart", DoBootchartCmd, 0},
};
static int BootchartInit(void)
MODULE_CONSTRUCTOR(void)
{
for (int i = 0; i < (int)(sizeof(g_bootchartCmds) / sizeof(g_bootchartCmds[0])); i++) {
g_bootchartCmds[i].index = AddCmdExecutor(
g_bootchartCmds[i].name, g_bootchartCmds[i].cmdExecutor);
PLUGIN_LOGI("BootchartInit %d", g_bootchartCmds[i].index);
}
return 0;
}
static void BootchartExit(void)
{
PLUGIN_LOGI("BootchartExit %d", g_bootchartCmds[0]);
for (int i = 0; i < (int)(sizeof(g_bootchartCmds) / sizeof(g_bootchartCmds[0])); i++) {
RemoveCmdExecutor(g_bootchartCmds[i].name, g_bootchartCmds[i].index);
}
PLUGIN_LOGI("DoBootchartStart now ...");
DoBootchartStart();
}
PLUGIN_CONSTRUCTOR(void)
MODULE_DESTRUCTOR(void)
{
PluginRegister("bootchart", NULL, BootchartInit, BootchartExit);
PLUGIN_LOGI("DoBootchartStop now ...");
DoBootchartStop();
}
/*
* 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 <string.h>
#include "init_module_engine.h"
#include "plugin_adapter.h"
static int bootchartEarlyHook(int stage, int prio, void *cookie)
{
char enable[4] = {}; // 4 enable size
uint32_t size = sizeof(enable);
SystemReadParam("persist.init.bootchart.enabled", enable, &size);
if (strcmp(enable, "1") != 0) {
PLUGIN_LOGI("bootchart disabled.");
return 0;
}
InitModuleMgrInstall("libbootchart");
PLUGIN_LOGI("bootchart enabled.");
return 0;
}
MODULE_CONSTRUCTOR(void)
{
// Depends on parameter service
InitAddPreCfgLoadHook(0, bootchartEarlyHook);
}
......@@ -20,13 +20,6 @@
#include <stdio.h>
#include "init_log.h"
#include "securec.h"
typedef struct {
char *name;
int (*cmdExecutor)(int id, const char *name, int argc, const char **argv);
int index;
} PluginCmd;
#ifndef PLUGIN_DOMAIN
#define PLUGIN_DOMAIN (BASE_DOMAIN + 6)
......@@ -46,4 +39,4 @@ typedef struct {
if (!(ret)) { \
exper; \
}
#endif
\ No newline at end of file
#endif
......@@ -16,7 +16,17 @@
#include "list.h"
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
/**
* @brief Initialize a double-linked list head
*
* All other list API should be initialized by this function.\n
*
* @param head list head, make sure head is valid pointer
* @return None
*/
void ListInit(struct ListNode *node)
{
if (node == NULL) {
......@@ -26,6 +36,13 @@ void ListInit(struct ListNode *node)
node->prev = node;
}
/**
* @brief Add a node to the end of the list
*
* @param head list head, make sure head is valid pointer
* @param item new node to be added
* @return None
*/
void ListAddTail(struct ListNode *head, struct ListNode *item)
{
if (head == NULL || item == NULL) {
......@@ -37,6 +54,13 @@ void ListAddTail(struct ListNode *head, struct ListNode *item)
head->prev = item;
}
/**
* @brief Remove a node from the list
*
* @param item the node to be removed from the list.
* This function does not free any memory within item.
* @return None
*/
void ListRemove(struct ListNode *item)
{
if (item == NULL) {
......@@ -45,3 +69,168 @@ void ListRemove(struct ListNode *item)
item->next->prev = item->prev;
item->prev->next = item->next;
}
/**
* @brief Add a node to the list with order
*
* @param head list head, make sure head is valid pointer
* @param item new node to be added
* @param compareProc comparison function for adding node
* if it is ascending order, this function should return an integer less than,
* equal to, or greater than zero if the first argument is considered to be
* respectively less than, equal to, or greater than the second.
* @return None
*/
void ListAddWithOrder(struct ListNode *head, struct ListNode *item, ListCompareProc compareProc)
{
ListNode *match;
int ret;
if (head == NULL || item == NULL || compareProc == NULL) {
return;
}
match = head->next;
while ((match != NULL) && (match != head)) {
ret = compareProc(match, item);
if (ret > 0) {
break;
}
match = match->next;
}
if (match == NULL) {
return;
}
// Insert
item->next = match;
item->prev = match->prev;
match->prev->next = item;
match->prev = item;
}
/**
* @brief Find a node by traversing the list
*
* @param head list head, make sure head is valid pointer.
* @param data comparing data.
* @param compareProc comparing function, return 0 if matched.
* @return the found node; return NULL if none is found.
*/
ListNode *ListFind(const ListNode *head, void *data, ListTraversalProc compareProc)
{
ListNode *match;
if ((head == NULL) || (compareProc == NULL)) {
return NULL;
}
match = head->next;
while ((match != NULL) && (match != head)) {
if (compareProc(match, data) == 0) {
return match;
}
match = match->next;
}
return NULL;
}
#define IS_REVERSE_ORDER(flags) (((flags) & TRAVERSE_REVERSE_ORDER) != 0)
#define IS_STOP_WHEN_ERROR(flags) (((flags) & TRAVERSE_STOP_WHEN_ERROR) != 0)
/**
* @brief Traversal the list with specified function
*
* @param head list head, make sure head is valid pointer.
* @param cookie optinal traversing data.
* @param traversalProc comparing function, return 0 if matched.
* @param flags optinal traversing flags:
* TRAVERSE_REVERSE_ORDER: traversing from last node to first node;
* default behaviour is from first node to last node
* TRAVERSE_STOP_WHEN_ERROR: stop traversing if traversalProc return non-zero
* default behaviour will ignore traversalProc return values
* @return return -1 for invalid input arguments.
* when TRAVERSE_STOP_WHEN_ERROR is specified, it will return errors from traversalProc
*/
int ListTraversal(ListNode *head, void *data, ListTraversalProc traversalProc, int flags)
{
int ret;
ListNode *match;
ListNode *next;
if ((head == NULL) || (traversalProc == NULL)) {
return -1;
}
if (IS_REVERSE_ORDER(flags)) {
match = head->prev;
} else {
match = head->next;
}
while ((match != NULL) && (match != head)) {
if (IS_REVERSE_ORDER(flags)) {
next = match->prev;
} else {
next = match->next;
}
ret = traversalProc(match, data);
if ((ret != 0) && IS_STOP_WHEN_ERROR(flags)) {
return ret;
}
match = next;
}
return 0;
}
static int listDestroyTraversal(ListNode *node, void *data)
{
ListDestroyProc destroyProc = (ListDestroyProc)data;
if (destroyProc == NULL) {
free((void *)node);
} else {
destroyProc(node);
}
return 0;
}
/**
* @brief Find a node by traversing the list
*
* @param head list head, make sure head is valid pointer.
* @param destroyProc destroy function; if NULL, it will free each node by default.
* @return None
*/
void ListRemoveAll(ListNode *head, ListDestroyProc destroyProc)
{
if (head == NULL) {
return;
}
ListTraversal(head, (void *)destroyProc, listDestroyTraversal, 0);
ListInit(head);
}
/**
* @brief Get list count
*
* @param head list head, make sure head is valid pointer.
* @return the count of nodes in the list; return 0 if error
*/
int ListGetCnt(const ListNode *head)
{
int cnt;
ListNode *node;
if (head == NULL) {
return 0;
}
cnt = 0;
ForEachListEntry(head, node) {
cnt++;
}
return cnt;
}
......@@ -14,8 +14,8 @@
import("//base/startup/init_lite/begetd.gni")
import("//build/ohos.gni")
ohos_shared_library("libpluginparamtest") {
sources = [ "plugin_param_test.c" ]
ohos_shared_library("libparamtestmodule") {
sources = [ "param_test_module.c" ]
include_dirs = [
"//base/startup/init_lite/services/include/param",
......@@ -36,23 +36,14 @@ ohos_shared_library("libpluginparamtest") {
"//third_party/bounds_checking_function:libsec_shared",
]
external_deps = [ "init:libinit_plugin_engine" ]
external_deps = [ "init:libinit_module_engine" ]
part_name = "init"
module_install_dir = "lib/plugin"
module_install_dir = "lib/init"
}
ohos_prebuilt_etc("plugin_param_test.cfg") {
source = "//base/startup/init_lite/test/plugintest/plugin_param_test.cfg"
part_name = "init"
module_install_dir = "etc/plugin"
}
group("pluginparamtest") {
group("paramtestmodule") {
if (param_test) {
deps = [
":libpluginparamtest",
":plugin_param_test.cfg",
]
deps = [ ":libparamtestmodule" ]
}
}
......@@ -15,19 +15,25 @@
#include <ctype.h>
#include <unistd.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include "plugin_test.h"
#include "init_param.h"
#include "init_plugin_engine.h"
#include "modulemgr.h"
#include "init_module_engine.h"
#include "securec.h"
#define MAX_COUNT 1000
#define TEST_CMD_NAME "param_randrom_write"
#define READ_DURATION 100000
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_LOGI("PluginParamCmdWriteParam argc %d %s", argc, argv[0]);
if ((argv == NULL) || (argc < 1)) {
return -1;
}
int maxCount = MAX_COUNT;
if (argc > 1) {
maxCount = atoi(argv[1]);
......@@ -47,23 +53,12 @@ static int PluginParamCmdWriteParam(int id, const char *name, int argc, const ch
return 0;
}
static int PluginParamTestInit(void)
MODULE_CONSTRUCTOR(void)
{
g_testCmdIndex = AddCmdExecutor(TEST_CMD_NAME, PluginParamCmdWriteParam);
PLUGIN_LOGI("PluginParamTestInit %d", g_testCmdIndex);
return 0;
}
static void PluginParamTestExit(void)
MODULE_DESTRUCTOR(void)
{
RemoveCmdExecutor(TEST_CMD_NAME, g_testCmdIndex);
}
PLUGIN_CONSTRUCTOR(void)
{
PluginRegister("pluginparamtest",
"/system/etc/plugin/plugin_param_test.cfg",
PluginParamTestInit, PluginParamTestExit);
PLUGIN_LOGI("PLUGIN_CONSTRUCTOR pluginInterface %p",
g_pluginInterface->pluginRegister);
}
......@@ -57,10 +57,10 @@ ohos_unittest("init_ut") {
"//base/startup/init_lite/services/init/init_service_socket.c",
"//base/startup/init_lite/services/init/standard/device.c",
"//base/startup/init_lite/services/init/standard/init.c",
"//base/startup/init_lite/services/init/standard/init_cmdexecutor.c",
"//base/startup/init_lite/services/init/standard/init_cmds.c",
"//base/startup/init_lite/services/init/standard/init_jobs.c",
"//base/startup/init_lite/services/init/standard/init_mount.c",
"//base/startup/init_lite/services/init/standard/init_plugin_manager.c",
"//base/startup/init_lite/services/init/standard/init_reboot.c",
"//base/startup/init_lite/services/init/standard/init_service.c",
"//base/startup/init_lite/services/init/standard/init_signal_handler.c",
......@@ -124,7 +124,6 @@ ohos_unittest("init_ut") {
"init/group_unittest.cpp",
"init/init_reboot_unittest.cpp",
"init/mount_unittest.cpp",
"init/plugin_unittest.cpp",
"init/service_file_unittest.cpp",
"init/service_socket_unittest.cpp",
"init/utils_unittest.cpp",
......@@ -140,6 +139,13 @@ ohos_unittest("init_ut") {
"ueventd/ueventd_config_unittest.cpp",
]
sources += [
"//base/startup/init_lite/interfaces/innerkits/hookmgr/hookmgr.c",
"//base/startup/init_lite/interfaces/innerkits/modulemgr/modulemgr.c",
"innerkits/hookmgr_unittest.cpp",
"innerkits/modulemgr_unittest.cpp",
]
configs = [ "//base/startup/init_lite/test/unittest:utest_config" ]
include_dirs = [
......@@ -208,7 +214,7 @@ ohos_unittest("init_ut") {
external_deps = [
"hiviewdfx_hilog_native:libhilog",
"init:libinit_plugin_engine",
"init:libinit_module_engine",
"utils_base:utils",
]
......@@ -250,5 +256,8 @@ ohos_unittest("init_ut") {
group("init_test") {
testonly = true
deps = [ ":init_ut" ]
deps = [
":init_ut",
"//base/startup/init_lite/test/moduletest:paramtestmodule",
]
}
/*
* 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.
*/
#include <cinttypes>
#include <gtest/gtest.h>
#include "hookmgr.h"
using namespace testing::ext;
using namespace std;
namespace init_ut {
class HookMgrUnitTest : public testing::Test {
public:
static void SetUpTestCase(void) {};
static void TearDownTestCase(void) {};
void SetUp() {};
void TearDown() {};
};
struct HookExecCtx {
int result;
int retErr;
};
static int OhosHookTestCommon(void *cookie, int result)
{
struct HookExecCtx *ctx;
if (cookie == NULL) {
return 0;
}
ctx = (struct HookExecCtx *)cookie;
ctx->result = result;
if (ctx->retErr) {
return -1;
}
return 0;
}
static int OhosTestHookRetOK(int stage, int priority, void *cookie)
{
return OhosHookTestCommon(cookie, 1);
}
static int OhosTestHookRetOKEx(int stage, int priority, void *cookie)
{
return OhosHookTestCommon(cookie, 2);
}
static int OhosTestHookRetOKEx2(int stage, int priority, void *cookie)
{
return OhosHookTestCommon(cookie, 3);
}
static void OhosHookPrint(const HOOK_INFO *hookInfo)
{
printf("\tstage[%02d] prio[%02d] hook[%p].\n", hookInfo->stage, hookInfo->prio, hookInfo->hook);
}
static void dumpAllHooks(HOOK_MGR *hookMgr)
{
printf("----------All Hooks---------------\n");
HookMgrTraversal(hookMgr, NULL, OhosHookPrint);
printf("----------------------------------\n\n");
}
#define STAGE_TEST_ONE 0
HWTEST_F(HookMgrUnitTest, HookMgrAdd_one_stage_unitest, TestSize.Level1)
{
int ret;
int cnt;
cnt = HookMgrGetStagesCnt(NULL);
EXPECT_EQ(cnt, 0);
// Add the first hook
ret = HookMgrAdd(NULL, STAGE_TEST_ONE, 0, OhosTestHookRetOK);
EXPECT_EQ(ret, 0);
cnt = HookMgrGetHooksCnt(NULL, STAGE_TEST_ONE);
EXPECT_EQ(cnt, 1);
cnt = HookMgrGetStagesCnt(NULL);
EXPECT_EQ(cnt, 1);
dumpAllHooks(NULL);
// Add the same hook with the same priority again
ret = HookMgrAdd(NULL, STAGE_TEST_ONE, 0, OhosTestHookRetOK);
EXPECT_EQ(ret, 0);
cnt = HookMgrGetHooksCnt(NULL, STAGE_TEST_ONE);
EXPECT_EQ(cnt, 1);
dumpAllHooks(NULL);
// Add the same hook with different priority
ret = HookMgrAdd(NULL, STAGE_TEST_ONE, 10, OhosTestHookRetOK);
EXPECT_EQ(ret, 0);
cnt = HookMgrGetHooksCnt(NULL, STAGE_TEST_ONE);
EXPECT_EQ(cnt, 2);
dumpAllHooks(NULL);
// Add the another hook
ret = HookMgrAdd(NULL, STAGE_TEST_ONE, 10, OhosTestHookRetOKEx);
EXPECT_EQ(ret, 0);
cnt = HookMgrGetHooksCnt(NULL, STAGE_TEST_ONE);
EXPECT_EQ(cnt, 3);
dumpAllHooks(NULL);
// Add the same hook with the same priority again
ret = HookMgrAdd(NULL, STAGE_TEST_ONE, 0, OhosTestHookRetOK);
EXPECT_EQ(ret, 0);
cnt = HookMgrGetHooksCnt(NULL, STAGE_TEST_ONE);
EXPECT_EQ(cnt, 3);
dumpAllHooks(NULL);
// Add the same hook with the same priority again
ret = HookMgrAdd(NULL, STAGE_TEST_ONE, 10, OhosTestHookRetOK);
EXPECT_EQ(ret, 0);
cnt = HookMgrGetHooksCnt(NULL, STAGE_TEST_ONE);
EXPECT_EQ(cnt, 3);
dumpAllHooks(NULL);
// Add the another hook
ret = HookMgrAdd(NULL, STAGE_TEST_ONE, 10, OhosTestHookRetOKEx);
EXPECT_EQ(ret, 0);
cnt = HookMgrGetHooksCnt(NULL, STAGE_TEST_ONE);
EXPECT_EQ(cnt, 3);
dumpAllHooks(NULL);
// Insert to the end of already exist prio
ret = HookMgrAdd(NULL, STAGE_TEST_ONE, 0, OhosTestHookRetOKEx);
EXPECT_EQ(ret, 0);
cnt = HookMgrGetHooksCnt(NULL, STAGE_TEST_ONE);
EXPECT_EQ(cnt, 4);
dumpAllHooks(NULL);
// Insert to the end of already exist prio
ret = HookMgrAdd(NULL, STAGE_TEST_ONE, 0, OhosTestHookRetOKEx2);
EXPECT_EQ(ret, 0);
cnt = HookMgrGetHooksCnt(NULL, STAGE_TEST_ONE);
EXPECT_EQ(cnt, 5);
dumpAllHooks(NULL);
// Insert a new prio hook
ret = HookMgrAdd(NULL, STAGE_TEST_ONE, 5, OhosTestHookRetOK);
EXPECT_EQ(ret, 0);
cnt = HookMgrGetHooksCnt(NULL, STAGE_TEST_ONE);
EXPECT_EQ(cnt, 6);
dumpAllHooks(NULL);
// Insert a new prio hook to the beginning
ret = HookMgrAdd(NULL, STAGE_TEST_ONE, -5, OhosTestHookRetOK);
EXPECT_EQ(ret, 0);
cnt = HookMgrGetHooksCnt(NULL, STAGE_TEST_ONE);
EXPECT_EQ(cnt, 7);
dumpAllHooks(NULL);
// All hooks are in the same stage
cnt = HookMgrGetStagesCnt(NULL);
EXPECT_EQ(cnt, 1);
// Delete all hooks in stage 0
HookMgrDel(NULL, STAGE_TEST_ONE, NULL);
cnt = HookMgrGetHooksCnt(NULL, 0);
EXPECT_EQ(cnt, 0);
cnt = HookMgrGetStagesCnt(NULL);
EXPECT_EQ(cnt, 0);
dumpAllHooks(NULL);
HookMgrDestroy(NULL);
}
HWTEST_F(HookMgrUnitTest, HookMgrDel_unitest, TestSize.Level1)
{
int ret;
int cnt;
HOOK_MGR *hookMgr = HookMgrCreate("test");
ASSERT_NE(hookMgr, nullptr);
// Add one, delete one
ret = HookMgrAdd(hookMgr, STAGE_TEST_ONE, 0, OhosTestHookRetOK);
EXPECT_EQ(ret, 0);
cnt = HookMgrGetHooksCnt(hookMgr, STAGE_TEST_ONE);
EXPECT_EQ(cnt, 1);
HookMgrDel(hookMgr, STAGE_TEST_ONE, OhosTestHookRetOK);
cnt = HookMgrGetHooksCnt(hookMgr, STAGE_TEST_ONE);
EXPECT_EQ(cnt, 0);
// Add three same hook with different prio, delete together
ret = HookMgrAdd(hookMgr, STAGE_TEST_ONE, 0, OhosTestHookRetOK);
EXPECT_EQ(ret, 0);
cnt = HookMgrGetHooksCnt(hookMgr, STAGE_TEST_ONE);
EXPECT_EQ(cnt, 1);
ret = HookMgrAdd(hookMgr, STAGE_TEST_ONE, 5, OhosTestHookRetOK);
EXPECT_EQ(ret, 0);
cnt = HookMgrGetHooksCnt(hookMgr, STAGE_TEST_ONE);
EXPECT_EQ(cnt, 2);
ret = HookMgrAdd(hookMgr, STAGE_TEST_ONE, 10, OhosTestHookRetOK);
EXPECT_EQ(ret, 0);
cnt = HookMgrGetHooksCnt(hookMgr, STAGE_TEST_ONE);
EXPECT_EQ(cnt, 3);
dumpAllHooks(hookMgr);
HookMgrDel(hookMgr, STAGE_TEST_ONE, OhosTestHookRetOK);
cnt = HookMgrGetHooksCnt(hookMgr, STAGE_TEST_ONE);
EXPECT_EQ(cnt, 0);
// Add three different hook with same prio, delete one by one
ret = HookMgrAdd(hookMgr, STAGE_TEST_ONE, 0, OhosTestHookRetOK);
EXPECT_EQ(ret, 0);
cnt = HookMgrGetHooksCnt(hookMgr, STAGE_TEST_ONE);
EXPECT_EQ(cnt, 1);
ret = HookMgrAdd(hookMgr, STAGE_TEST_ONE, 0, OhosTestHookRetOKEx);
EXPECT_EQ(ret, 0);
cnt = HookMgrGetHooksCnt(hookMgr, STAGE_TEST_ONE);
EXPECT_EQ(cnt, 2);
ret = HookMgrAdd(hookMgr, STAGE_TEST_ONE, 0, OhosTestHookRetOKEx2);
EXPECT_EQ(ret, 0);
cnt = HookMgrGetHooksCnt(hookMgr, STAGE_TEST_ONE);
EXPECT_EQ(cnt, 3);
dumpAllHooks(hookMgr);
HookMgrDel(hookMgr, STAGE_TEST_ONE, OhosTestHookRetOK);
cnt = HookMgrGetHooksCnt(hookMgr, STAGE_TEST_ONE);
EXPECT_EQ(cnt, 2);
dumpAllHooks(hookMgr);
HookMgrDel(hookMgr, STAGE_TEST_ONE, OhosTestHookRetOKEx2);
cnt = HookMgrGetHooksCnt(hookMgr, STAGE_TEST_ONE);
EXPECT_EQ(cnt, 1);
dumpAllHooks(hookMgr);
HookMgrDel(hookMgr, STAGE_TEST_ONE, OhosTestHookRetOKEx);
cnt = HookMgrGetHooksCnt(hookMgr, STAGE_TEST_ONE);
EXPECT_EQ(cnt, 0);
HookMgrDestroy(hookMgr);
}
HWTEST_F(HookMgrUnitTest, HookMgrExecute_unitest, TestSize.Level1)
{
int ret;
struct HookExecCtx ctx;
HOOK_EXEC_ARGS args;
ctx.result = 0;
ctx.retErr = 0;
args.flags = 0;
args.cookie = (void *)&ctx;
args.preHook = NULL;
args.postHook = NULL;
ret = HookMgrAdd(NULL, STAGE_TEST_ONE, 0, OhosTestHookRetOK);
EXPECT_EQ(ret, 0);
ret = HookMgrExecute(NULL, STAGE_TEST_ONE, &args);
EXPECT_EQ(ret, 0);
EXPECT_EQ(ctx.result, 1);
// Check ignore error
ctx.retErr = 1;
ret = HookMgrExecute(NULL, STAGE_TEST_ONE, &args);
EXPECT_EQ(ret, 0);
EXPECT_EQ(ctx.result, 1);
// Do not ignore return errors
ctx.retErr = 1;
args.flags = HOOK_EXEC_EXIT_WHEN_ERROR;
ret = HookMgrExecute(NULL, STAGE_TEST_ONE, &args);
ASSERT_NE(ret, 0);
EXPECT_EQ(ctx.result, 1);
args.flags = 0;
// Add another hook with same priority
ret = HookMgrAdd(NULL, STAGE_TEST_ONE, 0, OhosTestHookRetOKEx);
EXPECT_EQ(ret, 0);
ret = HookMgrExecute(NULL, STAGE_TEST_ONE, &args);
EXPECT_EQ(ret, 0);
EXPECT_EQ(ctx.result, 2);
// Add another hook with higher priority
ret = HookMgrAdd(NULL, STAGE_TEST_ONE, -1, OhosTestHookRetOKEx);
EXPECT_EQ(ret, 0);
ret = HookMgrExecute(NULL, STAGE_TEST_ONE, &args);
EXPECT_EQ(ret, 0);
EXPECT_EQ(ctx.result, 2);
HookMgrDel(NULL, STAGE_TEST_ONE, OhosTestHookRetOKEx);
ret = HookMgrExecute(NULL, STAGE_TEST_ONE, &args);
EXPECT_EQ(ret, 0);
EXPECT_EQ(ctx.result, 1);
}
} // namespace init_ut
......@@ -16,8 +16,8 @@
#include "init_group_manager.h"
#include "init_hashmap.h"
#include "init_param.h"
#include "init_plugin_engine.h"
#include "init_plugin_manager.h"
#include "init_module_engine.h"
#include "init_cmdexecutor.h"
#include "param_stub.h"
#include "init_utils.h"
#include "securec.h"
......@@ -26,7 +26,7 @@ using namespace testing::ext;
using namespace std;
namespace init_ut {
class PluginUnitTest : public testing::Test {
class ModuleMgrUnitTest : public testing::Test {
public:
static void SetUpTestCase(void) {};
static void TearDownTestCase(void) {};
......@@ -42,10 +42,9 @@ int TestCmdExecutor(int id, const char *name, int argc, const char **argv)
return 0;
}
HWTEST_F(PluginUnitTest, PluginAddCmd, TestSize.Level1)
HWTEST_F(ModuleMgrUnitTest, PluginAddCmd, TestSize.Level1)
{
InitServiceSpace();
PluginManagerInit();
const char *testName = "testCmd1";
const char *cmdContent = "testCmd1 test1 test2 test3";
int cmdExecId1 = AddCmdExecutor(testName, TestCmdExecutor);
......@@ -77,24 +76,58 @@ HWTEST_F(PluginUnitTest, PluginAddCmd, TestSize.Level1)
RemoveCmdExecutor("testCmd4", cmdExecId4);
}
static int PluginTestInit(void)
HWTEST_F(ModuleMgrUnitTest, ModuleInstallTest, TestSize.Level1)
{
g_cmdExecId = AddCmdExecutor("testCmd4", TestCmdExecutor);
return 0;
}
int ret;
int cnt;
static void PluginTestExit(void)
{
RemoveCmdExecutor("testCmd4", g_cmdExecId);
}
// Create module manager
MODULE_MGR *moduleMgr = ModuleMgrCreate("init");
ASSERT_NE(moduleMgr, nullptr);
cnt = ModuleMgrGetCnt(moduleMgr);
ASSERT_EQ(cnt, 0);
HWTEST_F(PluginUnitTest, PluginInstallTest, TestSize.Level1)
{
const char *moduleName = "testplugin";
PluginRegister(moduleName,
"/home/axw/init_ut/etc/init/plugin_param_test.cfg",
PluginTestInit, PluginTestExit);
PluginInstall(moduleName, NULL);
PluginUninstall(moduleName);
// Install one module
ret = ModuleMgrInstall(moduleMgr, "libbootchart", 0, NULL);
ASSERT_EQ(ret, 0);
cnt = ModuleMgrGetCnt(moduleMgr);
ASSERT_EQ(cnt, 1);
// Uninstall the module
ModuleMgrUninstall(moduleMgr, "libbootchart");
cnt = ModuleMgrGetCnt(moduleMgr);
ASSERT_EQ(cnt, 0);
// Install two module
ret = ModuleMgrInstall(moduleMgr, "libbootchart", 0, NULL);
ASSERT_EQ(ret, 0);
cnt = ModuleMgrGetCnt(moduleMgr);
ASSERT_EQ(cnt, 1);
ret = ModuleMgrInstall(moduleMgr, "notexist", 0, NULL);
ASSERT_NE(ret, 0);
cnt = ModuleMgrGetCnt(moduleMgr);
ASSERT_EQ(cnt, 1);
// Uninstall the module
ModuleMgrUninstall(moduleMgr, "libbootchart");
cnt = ModuleMgrGetCnt(moduleMgr);
ASSERT_EQ(cnt, 0);
ModuleMgrUninstall(moduleMgr, "notexist");
cnt = ModuleMgrGetCnt(moduleMgr);
ASSERT_EQ(cnt, 0);
ModuleMgrDestroy(moduleMgr);
// Scan all modules
moduleMgr = ModuleMgrScan("init");
ASSERT_NE(moduleMgr, nullptr);
cnt = ModuleMgrGetCnt(moduleMgr);
ASSERT_NE(cnt, 0);
ModuleMgrUninstall(moduleMgr, NULL);
cnt = ModuleMgrGetCnt(moduleMgr);
ASSERT_EQ(cnt, 0);
ModuleMgrDestroy(moduleMgr);
}
} // namespace init_ut
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册