add init cmd bootevent and optimize

Signed-off-by: cheng_jinsong <chengjinsong2@huawei.com>
Change-Id: Ibb5657d43f05fc842946cad2bf82e7cf21843565
This commit is contained in:
cheng_jinsong 2022-10-11 07:47:40 -07:00
parent 420c8b9edd
commit 733b3611ee
10 changed files with 199 additions and 61 deletions

View File

@ -33,11 +33,13 @@ enum INIT_BOOTSTAGE {
INIT_SERVICE_PARSE = 35,
INIT_POST_PERSIST_PARAM_LOAD = 40,
INIT_POST_CFG_LOAD = 50,
INIT_CMD_RECORD = 51,
INIT_REBOOT = 55,
INIT_SERVICE_CLEAR = 56,
INIT_SERVICE_DUMP = 57,
INIT_SERVICE_FORK_BEFORE = 58,
INIT_SERVICE_SET_PERMS = 59,
INIT_SERVICE_FORK_AFTER = 60,
INIT_JOB_PARSE = 70,
};
@ -97,6 +99,15 @@ typedef struct tagSERVICE_INFO_CTX {
const char *reserved; /* reserved info */
} SERVICE_INFO_CTX;
/**
* @brief init cmd info
*/
typedef struct InitCmdInfo {
const char *cmdName; /* cmd name */
const char *cmdContent; /* cmd content */
const char *reserved; /* reserved info */
} INIT_CMD_INFO;
/**
* @brief service config parse hook function prototype
*

View File

@ -30,9 +30,7 @@ static int main_cmd(BShellHandle shell, int argc, char **argv)
printf("dump service info \n");
CmdClientInit(INIT_CONTROL_FD_SOCKET_PATH, ACTION_DUMP, argv[1]);
} else if (argc == DUMP_SERVICE_BOOTEVENT_CMD_ARGS) {
if (strcmp(argv[1], "bootevent") == 0) {
printf("dump service bootevent info \n");
} else if (strcmp(argv[1], "parameter_service") == 0) {
if (strcmp(argv[1], "parameter_service") == 0) {
printf("dump parameter service info \n");
}
size_t serviceNameLen = strlen(argv[1]) + strlen(argv[2]) + 2; // 2 is \0 and #
@ -48,29 +46,32 @@ static int main_cmd(BShellHandle shell, int argc, char **argv)
return 0;
}
static int ClearBootEvent(BShellHandle shell, int argc, char **argv)
static int BootEventEnable(BShellHandle shell, int argc, char **argv)
{
return SystemSetParameter("ohos.servicectrl.clear", "bootevent");
if (SystemSetParameter("persist.init.bootevent.enable", "true") == 0) {
printf("bootevent enabled\n");
}
return 0;
}
static int SaveBootEvent(BShellHandle shell, int argc, char **argv)
static int BootEventDisable(BShellHandle shell, int argc, char **argv)
{
return SystemSetParameter("ohos.servicectrl.save", "bootevent");
if (SystemSetParameter("persist.init.bootevent.enable", "false") == 0) {
printf("bootevent disabled\n");
}
return 0;
}
MODULE_CONSTRUCTOR(void)
{
const CmdInfo infos[] = {
{"dump_service", main_cmd, "dump one service info by serviceName", "dump_service serviceName", NULL},
{"dump_service", main_cmd, "dump one service bootevent", "dump_service serviceName bootevent", NULL},
{"dump_service", main_cmd, "dump all services info", "dump_service all", NULL},
{"dump_service", main_cmd, "dump parameter-service trigger",
"dump_service parameter_service trigger", "dump_service parameter_service trigger"},
{"dump_service", main_cmd, "dump all services bootevent", "dump_service all bootevent", NULL},
{"service", ClearBootEvent, "Clear all services bootevent", "service clear bootevent",
"service clear bootevent"},
{"service", SaveBootEvent, "Save all services bootevent", "service save bootevent",
"service save bootevent"},
"dump_service parameter_service trigger", NULL},
{"bootevent", BootEventEnable, "bootevent enable", "bootevent enable",
"bootevent enable"},
{"bootevent", BootEventDisable, "bootevent disable", "bootevent disable",
"bootevent disable"},
};
for (size_t i = 0; i < sizeof(infos) / sizeof(infos[0]); i++) {
BShellEnvRegisterCmd(GetShellHandle(), &infos[i]);

View File

@ -21,6 +21,7 @@ const.build.characteristics=default
const.product.model=ohos
const.product.name="OpenHarmony 3.2"
persist.sys.usb.config=hdc
persist.init.bootevent.enable=true
const.sandbox=enable
const.product.devicetype=default
const.software.model=default

View File

@ -28,6 +28,7 @@ startup.appspawn. = root:root:0750
startup.uevent. = ueventd:ueventd:0775
persist.init.debug. = root:root:0775:int
persist.init.bootevent.enable = root:root:0775:bool
persist.appspawn. = root:root:0775
#udid and sn, only read

View File

@ -38,6 +38,25 @@
#include "init_utils.h"
#include "securec.h"
#ifndef OHOS_LITE
#include "hookmgr.h"
#include "bootstage.h"
/**
* init cmd hooking execute
*/
static void InitCmdHookExecute(const char *cmdName, const char *cmdContent, INIT_TIMING_STAT *cmdTimer)
{
INIT_CMD_INFO context;
context.cmdName = cmdName;
context.cmdContent = cmdContent;
context.reserved = (const char *)cmdTimer;
(void)HookMgrExecute(GetBootStageHookMgr(), INIT_CMD_RECORD, (void *)(&context), NULL);
}
#endif
static char *AddOneArg(const char *param, size_t paramLen)
{
int valueCount = 1;
@ -719,6 +738,9 @@ void DoCmdByName(const char *name, const char *cmdContent)
}
(void)clock_gettime(CLOCK_MONOTONIC, &cmdTimer.endTime);
long long diff = InitDiffTime(&cmdTimer);
#ifndef OHOS_LITE
InitCmdHookExecute(name, cmdContent, &cmdTimer);
#endif
INIT_LOGV("Execute command \"%s %s\" took %lld ms", name, cmdContent, diff / 1000); // 1000 is convert us to ms
}
@ -751,5 +773,8 @@ void DoCmdByIndex(int index, const char *cmdContent)
}
(void)clock_gettime(CLOCK_MONOTONIC, &cmdTimer.endTime);
long long diff = InitDiffTime(&cmdTimer);
#ifndef OHOS_LITE
InitCmdHookExecute(cmdName, cmdContent, &cmdTimer);
#endif
INIT_LOGV("Execute command \"%s %s\" took %lld ms", cmdName, cmdContent, diff / 1000); // 1000 is convert us to ms
}

View File

@ -385,6 +385,12 @@ int ServiceStart(Service *service)
INIT_LOGI("Service %s(pid %d) started", service->name, pid);
service->pid = pid;
NotifyServiceChange(service, SERVICE_STARTED);
#ifndef OHOS_LITE
/*
* after service fork hooks
*/
ServiceHookExecute(service->name, (const char *)&pid, INIT_SERVICE_FORK_AFTER);
#endif
return SERVICE_SUCCESS;
}

View File

@ -15,6 +15,7 @@
#include <stdbool.h>
#include "init_module_engine.h"
#include "init_cmdexecutor.h"
#include "trigger_manager.h"
#include "init_log.h"
#include "plugin_adapter.h"
@ -23,17 +24,23 @@
#include "bootstage.h"
#include "securec.h"
#include "init_utils.h"
#include "init_cmds.h"
#define BOOT_EVENT_PARA_PREFIX "bootevent."
#define BOOT_EVENT_PARA_PREFIX_LEN 10
#define BOOT_EVENT_TIMESTAMP_MAX_LEN 50
#define BOOT_EVENT_FILEPATH_MAX_LEN 60
#define BOOT_EVENT_FINISH 2
#define SECTOMSEC 1000000
#define SECTONSEC 1000000000
#define MSECTONSEC 1000
#define SAVEINITBOOTEVENTMSEC 100000
#define BOOTEVENT_OUTPUT_PATH "/data/service/el0/startup/init/"
static int g_bootEventNum = 0;
// check bootevent enable
static int g_bootEventEnable = 1;
enum {
BOOTEVENT_FORK,
BOOTEVENT_READY,
@ -43,6 +50,7 @@ enum {
typedef struct tagBOOT_EVENT_PARAM_ITEM {
ListNode node;
char *paramName;
int pid;
struct timespec timestamp[BOOTEVENT_MAX];
} BOOT_EVENT_PARAM_ITEM;
@ -112,7 +120,7 @@ static void AddInitBootEvent(const char *bootEventName)
return;
}
BOOT_EVENT_PARAM_ITEM *item = malloc(sizeof(BOOT_EVENT_PARAM_ITEM));
BOOT_EVENT_PARAM_ITEM *item = calloc(1, sizeof(BOOT_EVENT_PARAM_ITEM));
if (item == NULL) {
return;
}
@ -132,6 +140,15 @@ static void AddInitBootEvent(const char *bootEventName)
#define BOOT_EVENT_BOOT_COMPLETED "bootevent.boot.completed"
static void BootEventDestroy(ListNode *node)
{
BOOT_EVENT_PARAM_ITEM *bootEvent = (BOOT_EVENT_PARAM_ITEM *)node;
INIT_CHECK(bootEvent->paramName == NULL, free((void *)bootEvent->paramName));
free((void *)bootEvent);
}
static int SaveServiceBootEvent();
static void BootEventParaFireByName(const char *paramName)
{
ListNode *found = NULL;
@ -158,12 +175,20 @@ static void BootEventParaFireByName(const char *paramName)
// All parameters are fired, set boot completed now ...
INIT_LOGI("All boot events are fired, boot complete now ...");
SystemWriteParam(BOOT_EVENT_BOOT_COMPLETED, "true");
g_bootEventEnable = BOOT_EVENT_FINISH;
SaveServiceBootEvent();
const char *clearBootEventArgv[] = {"bootevent"};
// clear servie extra data
PluginExecCmd("clear", ARRAY_LENGTH(clearBootEventArgv), clearBootEventArgv);
return;
}
#define BOOT_EVENT_FIELD_NAME "bootevents"
static void ServiceParseBootEventHook(SERVICE_PARSE_CTX *serviceParseCtx)
{
if (g_bootEventEnable == 0) {
return;
}
int cnt;
cJSON *bootEvents = cJSON_GetObjectItem(serviceParseCtx->serviceNode, BOOT_EVENT_FIELD_NAME);
@ -198,11 +223,54 @@ static void ServiceParseBootEventHook(SERVICE_PARSE_CTX *serviceParseCtx)
}
}
static void AddCmdBootEvent(int argc, const char **argv)
{
if (argc < 4) { // 4 is min args cmd boot event required
return;
}
BOOT_EVENT_PARAM_ITEM *item = calloc(1, sizeof(BOOT_EVENT_PARAM_ITEM));
if (item == NULL) {
return;
}
OH_ListInit(&item->node);
item->timestamp[BOOTEVENT_FORK] = ((INIT_TIMING_STAT *)argv[3])->startTime; // 3 args
item->timestamp[BOOTEVENT_READY] = ((INIT_TIMING_STAT *)argv[3])->endTime; // 3 args
int cmdLen = strlen(argv[1]) + strlen(argv[2]) + 1; // 2 args 1 '\0'
item->paramName = calloc(1, cmdLen);
if (item->paramName == NULL) {
free(item);
return;
}
for (int i = 1; i < 3; i++) { // 3 cmd content end
INIT_CHECK_ONLY_ELOG(strcat_s(item->paramName, cmdLen, argv[i]) >= 0, "combine cmd args failed");
}
OH_ListAddTail(&bootEventList, (ListNode *)&item->node);
return;
}
static int DoBootEventCmd(int id, const char *name, int argc, const char **argv)
{
if (g_bootEventEnable == BOOT_EVENT_FINISH) {
return 0;
}
// clear init boot events that recorded before persist param read
if (g_bootEventEnable == 0) {
const char *clearBootEventArgv[] = {"bootevent"};
PluginExecCmd("clear", ARRAY_LENGTH(clearBootEventArgv), clearBootEventArgv);
OH_ListRemoveAll(&bootEventList, BootEventDestroy);
g_bootEventEnable = BOOT_EVENT_FINISH;
return 0;
}
PLUGIN_CHECK(argc >= 1, return -1, "Invalid parameter");
if (strcmp(argv[0], "init") == 0) {
if (argc < 2) { // 2 args
return 0;
}
AddInitBootEvent(argv[1]);
} else if (strcmp(argv[0], "cmd") == 0) {
AddCmdBootEvent(argc, argv);
} else {
// argv[0] samgr.ready.true
BootEventParaFireByName(argv[0]);
@ -210,15 +278,15 @@ static int DoBootEventCmd(int id, const char *name, int argc, const char **argv)
return 0;
}
static int AddItemToJson(cJSON *root, const char *name, double startTime, int tid, double durTime)
static int AddItemToJson(cJSON *root, const char *name, double startTime, int pid, double durTime)
{
cJSON *obj = cJSON_CreateObject(); // release obj at traverse done
INIT_CHECK_RETURN_VALUE(obj != NULL, -1);
cJSON_AddStringToObject(obj, "name", name);
cJSON_AddNumberToObject(obj, "ts", startTime);
cJSON_AddStringToObject(obj, "ph", "X");
cJSON_AddNumberToObject(obj, "pid", 0);
cJSON_AddNumberToObject(obj, "tid", tid);
cJSON_AddNumberToObject(obj, "pid", pid);
cJSON_AddNumberToObject(obj, "tid", pid);
cJSON_AddNumberToObject(obj, "dur", durTime);
cJSON_AddItemToArray(root, obj);
return 0;
@ -226,25 +294,35 @@ static int AddItemToJson(cJSON *root, const char *name, double startTime, int ti
static int BootEventTraversal(ListNode *node, void *root)
{
static int tid = 1; // 1 boot event start num
static int start = 0;
BOOT_EVENT_PARAM_ITEM *item = (BOOT_EVENT_PARAM_ITEM *)node;
double forkTime = item->timestamp[BOOTEVENT_FORK].tv_sec * SECTOMSEC +
(double)item->timestamp[BOOTEVENT_FORK].tv_nsec / MSECTONSEC;
double readyTime = item->timestamp[BOOTEVENT_READY].tv_sec * SECTOMSEC +
(double)item->timestamp[BOOTEVENT_READY].tv_nsec / MSECTONSEC;
double durTime = readyTime - forkTime;
if (tid == 1) {
// set time datum is 0
if (item->pid == 0) {
if (durTime < SAVEINITBOOTEVENTMSEC) {
return 0;
}
item->pid = 1; // 1 is init pid
}
if (start == 0) {
// set trace start time 0
INIT_CHECK_RETURN_VALUE(AddItemToJson((cJSON *)root, item->paramName, 0,
1, 0) == 0, -1);
start++;
}
INIT_CHECK_RETURN_VALUE(AddItemToJson((cJSON *)root, item->paramName, forkTime,
tid++, durTime > 0 ? durTime : 0) == 0, -1);
item->pid, durTime > 0 ? durTime : 0) == 0, -1);
return 0;
}
static int SaveServiceBootEvent(int id, const char *name, int argc, const char **argv)
static int SaveServiceBootEvent()
{
if (g_bootEventEnable == 0) {
return 0;
}
time_t nowTime = time(NULL);
INIT_CHECK_RETURN_VALUE(nowTime > 0, -1);
struct tm *p = localtime(&nowTime);
@ -281,36 +359,10 @@ static int ParamSetBootEventHook(const HOOK_INFO *hookInfo, void *cookie)
{
if (g_executorId == -1) {
g_executorId = AddCmdExecutor("bootevent", DoBootEventCmd);
AddCmdExecutor("save.bootevent", SaveServiceBootEvent);
}
return 0;
}
static void DumpServiceBootEvent(SERVICE_INFO_CTX *serviceCtx)
{
if (serviceCtx->reserved != NULL && strcmp(serviceCtx->reserved, "bootevent") != 0) {
return;
}
for (int i = HOOK_ID_BOOTEVENT; i < HOOK_ID_BOOTEVENT_MAX; i++) {
ServiceExtData *serviceExtData = GetServiceExtData(serviceCtx->serviceName, i);
if (serviceExtData == NULL) {
return;
}
BOOT_EVENT_PARAM_ITEM *item = (BOOT_EVENT_PARAM_ITEM *)serviceExtData->data;
char bootEventForkTimeStamp[BOOT_EVENT_TIMESTAMP_MAX_LEN] = "";
char bootEventReadyTimeStamp[BOOT_EVENT_TIMESTAMP_MAX_LEN] = "";
INIT_CHECK_ONLY_RETURN(sprintf_s(bootEventForkTimeStamp, BOOT_EVENT_TIMESTAMP_MAX_LEN, "%f",
item->timestamp[BOOTEVENT_FORK].tv_sec +
(double)item->timestamp[BOOTEVENT_FORK].tv_nsec / SECTONSEC) >= 0);
INIT_CHECK_ONLY_RETURN(sprintf_s(bootEventReadyTimeStamp, BOOT_EVENT_TIMESTAMP_MAX_LEN, "%f",
(long)item->timestamp[BOOTEVENT_READY].tv_sec +
(double)item->timestamp[BOOTEVENT_READY].tv_nsec / SECTONSEC) >= 0);
printf("\t%-20.20s\t%-50s\t%-20.20s\t%-20.20s\n", serviceCtx->serviceName, item->paramName,
bootEventForkTimeStamp, bootEventReadyTimeStamp);
}
return;
}
static void ClearServiceBootEvent(SERVICE_INFO_CTX *serviceCtx)
{
if (serviceCtx->reserved == NULL || strcmp(serviceCtx->reserved, "bootevent") == 0) {
@ -322,29 +374,65 @@ static void ClearServiceBootEvent(SERVICE_INFO_CTX *serviceCtx)
free(((BOOT_EVENT_PARAM_ITEM *)extData->data)->paramName);
OH_ListRemove(&((BOOT_EVENT_PARAM_ITEM *)extData->data)->node);
DelServiceExtData(serviceCtx->serviceName, i);
g_bootEventNum--;
}
// clear service extra data first
return;
}
if (strcmp(serviceCtx->reserved, "clearInitBootevent") == 0) {
// clear init boot event
OH_ListRemoveAll(&bootEventList, BootEventDestroy);
g_bootEventNum = 0;
}
return;
}
static void SetServiceBootEventFork(SERVICE_INFO_CTX *serviceCtx)
{
if (g_bootEventEnable == 0) {
return;
}
for (int i = HOOK_ID_BOOTEVENT; i < HOOK_ID_BOOTEVENT_MAX; i++) {
ServiceExtData *extData = GetServiceExtData(serviceCtx->serviceName, i);
if (extData == NULL || ((BOOT_EVENT_PARAM_ITEM *)extData->data)->timestamp[BOOTEVENT_FORK].tv_sec != 0) {
if (extData == NULL) {
return;
}
if (serviceCtx->reserved != NULL) {
((BOOT_EVENT_PARAM_ITEM *)extData->data)->pid = *((int *)serviceCtx->reserved);
continue;
}
INIT_CHECK_ONLY_RETURN(clock_gettime(CLOCK_MONOTONIC,
&(((BOOT_EVENT_PARAM_ITEM *)extData->data)->timestamp[BOOTEVENT_FORK])) == 0);
}
return;
}
static int GetBootEventFlag(const HOOK_INFO *info, void *cookie)
{
char BootEventOpen[6] = ""; // 6 is length of bool value
uint32_t len = sizeof(BootEventOpen);
SystemReadParam("persist.init.bootevent.enable", BootEventOpen, &len);
if (strcmp(BootEventOpen, "true") != 0) {
g_bootEventEnable = 0;
}
return 0;
}
static int RecordInitCmd(const HOOK_INFO *info, void *cookie)
{
INIT_CMD_INFO *cmdCtx = (INIT_CMD_INFO *)cookie;
const char *bootEventArgv[] = {"cmd", cmdCtx->cmdName, cmdCtx->cmdContent, cmdCtx->reserved};
return DoBootEventCmd(0, NULL, ARRAY_LENGTH(bootEventArgv), bootEventArgv);
}
MODULE_CONSTRUCTOR(void)
{
HOOK_INFO info = {INIT_CMD_RECORD, 0, RecordInitCmd, NULL};
HookMgrAddEx(GetBootStageHookMgr(), &info);
InitAddServiceHook(SetServiceBootEventFork, INIT_SERVICE_FORK_BEFORE);
InitAddServiceHook(SetServiceBootEventFork, INIT_SERVICE_FORK_AFTER);
InitAddServiceHook(ClearServiceBootEvent, INIT_SERVICE_CLEAR);
InitAddServiceHook(DumpServiceBootEvent, INIT_SERVICE_DUMP);
InitAddServiceParseHook(ServiceParseBootEventHook);
InitAddGlobalInitHook(0, ParamSetBootEventHook);
InitAddPostPersistParamLoadHook(0, GetBootEventFlag);
}

View File

@ -119,6 +119,8 @@ static int CmdClear(int id, const char *name, int argc, const char **argv)
HookMgrExecute(GetBootStageHookMgr(), INIT_SERVICE_CLEAR, (void *)&ctx, NULL);
node = GetNextGroupNode(NODE_TYPE_SERVICES, node);
}
ctx.reserved = "clearInitBootevent";
HookMgrExecute(GetBootStageHookMgr(), INIT_SERVICE_CLEAR, (void *)&ctx, NULL);
return 0;
}

View File

@ -35,7 +35,6 @@ const ParamCmdInfo *GetServiceCtl(size_t *size)
{"ohos.servicectrl.install", "install", "install" },
{"ohos.servicectrl.uninstall", "uninstall", "uninstall" },
{"ohos.servicectrl.clear", "clear", "clear" },
{"ohos.servicectrl.save", "save.bootevent", "save.bootevent" },
{"ohos.servicectrl.bootchart", "bootchart", "bootchart" },
{"ohos.servicectrl.timer_start", "timer_start", "timer_start " },
{"ohos.servicectrl.timer_stop", "timer_stop", "timer_stop" },

View File

@ -308,20 +308,24 @@ HWTEST_F(ServiceUnitTest, TestServiceBootEventHook, TestSize.Level1)
serviceInfoContext.reserved = "bootevent";
HookMgrExecute(GetBootStageHookMgr(), INIT_GLOBAL_INIT, nullptr, nullptr);
(void)HookMgrExecute(GetBootStageHookMgr(), INIT_SERVICE_DUMP, (void *)(&serviceInfoContext), NULL);
cJSON *fileRoot = cJSON_Parse(serviceStr);
ASSERT_NE(nullptr, fileRoot);
PluginExecCmd("clear", 0, nullptr);
ParseAllServices(fileRoot);
(void)HookMgrExecute(GetBootStageHookMgr(), INIT_SERVICE_FORK_BEFORE, (void *)(&serviceInfoContext), NULL);
SystemWriteParam("bootevent.bootevent1", "true");
SystemWriteParam("bootevent.bootevent1", "true");
SystemWriteParam("bootevent.bootevent2", "true");
serviceInfoContext.reserved = NULL;
(void)HookMgrExecute(GetBootStageHookMgr(), INIT_SERVICE_FORK_BEFORE, (void *)(&serviceInfoContext), NULL);
const char *initBootevent[] = {"init", "test"};
PluginExecCmd("bootevent", ARRAY_LENGTH(initBootevent), initBootevent);
PluginExecCmd("save.bootevent", 0, nullptr);
(void)HookMgrExecute(GetBootStageHookMgr(), INIT_SERVICE_DUMP, (void *)(&serviceInfoContext), NULL);
(void)HookMgrExecute(GetBootStageHookMgr(), INIT_SERVICE_CLEAR, (void *)(&serviceInfoContext), NULL);
PluginExecCmd("clear", 0, nullptr);
const char *initBooteventDup[] = {"init", "test"};
PluginExecCmd("bootevent", ARRAY_LENGTH(initBooteventDup), initBooteventDup);
const char *initBooteventErr[] = {"init"};
PluginExecCmd("bootevent", ARRAY_LENGTH(initBooteventErr), initBooteventErr);
SystemWriteParam("bootevent.bootevent1", "true");
SystemWriteParam("bootevent.bootevent2", "true");
SystemWriteParam("bootevent.bootevent2", "true");
SystemWriteParam("persist.init.bootevent.enable", "false");
HookMgrExecute(GetBootStageHookMgr(), INIT_POST_PERSIST_PARAM_LOAD, NULL, NULL);
cJSON_Delete(fileRoot);
}