From 3eed80cd1397d00dbefd574412959dcc7b4ce7ed Mon Sep 17 00:00:00 2001 From: cheng_jinsong Date: Mon, 22 Aug 2022 11:25:44 +0800 Subject: [PATCH] add save bootevent command and unittest Signed-off-by: cheng_jinsong Change-Id: I545b11b54564ed2cba2e3df80b518a5b8cdce8d0 --- services/etc/init.cfg | 3 +- services/modules/bootchart/bootchart.c | 14 ++-- services/modules/bootevent/bootevent.c | 76 ++++++++++++++++++- services/param/watcher/etc/param_watcher.cfg | 3 +- .../param/watcher/proxy/watcher_manager.cpp | 1 + test/unittest/init/service_unittest.cpp | 65 ++++++++++------ 6 files changed, 127 insertions(+), 35 deletions(-) diff --git a/services/etc/init.cfg b/services/etc/init.cfg index ab2c8bd7..7d02f6f8 100755 --- a/services/etc/init.cfg +++ b/services/etc/init.cfg @@ -17,9 +17,10 @@ "chmod 0771 /data", "mkdir /data/service 0711 root root", "mkdir /data/service/el0 0711 root root", + "mkdir /data/service/el0/startup 0755 root root", + "mkdir /data/service/el0/startup/init 0755 root root", "mount configfs none /config nodev noexec nosuid", "load_persist_params ", - "mkdir /data/bootchart 0755 root root", "bootchart start", "chown access_token access_token /dev/access_token_id", "chmod 0666 /dev/access_token_id" diff --git a/services/modules/bootchart/bootchart.c b/services/modules/bootchart/bootchart.c index 188fcc53..2e445180 100644 --- a/services/modules/bootchart/bootchart.c +++ b/services/modules/bootchart/bootchart.c @@ -29,6 +29,7 @@ #include "securec.h" #define NANO_PRE_JIFFY 10000000 +#define BOOTCHART_OUTPUT_PATH "/data/service/el0/startup/init/" static BootchartCtrl *g_bootchartCtrl = NULL; @@ -80,10 +81,10 @@ static void BootchartLogHeader(void) uint32_t len = sizeof(release); (void)SystemReadParam("const.ohos.releasetype", release, &len); char *cmdLine = ReadFileToBuffer("/proc/cmdline", g_bootchartCtrl->buffer, g_bootchartCtrl->bufferSize); - PLUGIN_CHECK(cmdLine != NULL, return, "Failed to open file /data/bootchart/header"); + PLUGIN_CHECK(cmdLine != NULL, return, "Failed to open file "BOOTCHART_OUTPUT_PATH"header"); - FILE *file = fopen("/data/bootchart/header", "we"); - PLUGIN_CHECK(file != NULL, return, "Failed to open file /data/bootchart/header"); + FILE *file = fopen(BOOTCHART_OUTPUT_PATH"header", "we"); + PLUGIN_CHECK(file != NULL, return, "Failed to open file "BOOTCHART_OUTPUT_PATH"header"); (void)fprintf(file, "version = openharmony init\n"); (void)fprintf(file, "title = Boot chart for openharmony (%s)\n", date); @@ -162,9 +163,9 @@ static void bootchartLogProcess(FILE *log) static void *BootchartThreadMain(void *data) { PLUGIN_LOGI("bootcharting start"); - FILE *statFile = fopen("/data/bootchart/proc_stat.log", "w"); - FILE *procFile = fopen("/data/bootchart/proc_ps.log", "w"); - FILE *diskFile = fopen("/data/bootchart/proc_diskstats.log", "w"); + FILE *statFile = fopen(BOOTCHART_OUTPUT_PATH"proc_stat.log", "w"); + FILE *procFile = fopen(BOOTCHART_OUTPUT_PATH"proc_ps.log", "w"); + FILE *diskFile = fopen(BOOTCHART_OUTPUT_PATH"proc_diskstats.log", "w"); do { if (statFile == NULL || procFile == NULL || diskFile == NULL) { PLUGIN_LOGE("Failed to open file"); @@ -219,7 +220,6 @@ static void BootchartDestory(void) static int DoBootchartStart(void) { - mkdir("/data/bootchart", S_IRWXU | S_IRWXG | S_IRWXO); if (g_bootchartCtrl != NULL) { PLUGIN_LOGI("bootcharting has been start"); return 0; diff --git a/services/modules/bootevent/bootevent.c b/services/modules/bootevent/bootevent.c index f5f77538..8ab01501 100755 --- a/services/modules/bootevent/bootevent.c +++ b/services/modules/bootevent/bootevent.c @@ -22,10 +22,16 @@ #include "init_service.h" #include "bootstage.h" #include "securec.h" +#include "init_utils.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 SECTOMSEC 1000000 +#define SECTONSEC 1000000000 +#define MSECTONSEC 1000 +#define BOOTEVENT_OUTPUT_PATH "/data/service/el0/startup/init/" static int g_bootEventNum = 0; enum { @@ -172,11 +178,71 @@ static int DoBootEventCmd(int id, const char *name, int argc, const char **argv) return 0; } +static int AddItemToJson(cJSON *root, const char *name, double startime, int tid, 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", startime); + cJSON_AddStringToObject(obj, "ph", "X"); + cJSON_AddNumberToObject(obj, "pid", 0); + cJSON_AddNumberToObject(obj, "tid", tid); + cJSON_AddNumberToObject(obj, "dur", durTime); + cJSON_AddItemToArray(root, obj); + return 0; +} + +static int BooteventTraversal(ListNode *node, void *root) +{ + static int tid = 1; // 1 bootevent start num + 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 + INIT_CHECK_RETURN_VALUE(AddItemToJson((cJSON *)root, item->paramName, 0, + 1, 0) == 0, -1); + } + INIT_CHECK_RETURN_VALUE(AddItemToJson((cJSON *)root, item->paramName, forkTime, + tid++, durTime > 0 ? durTime : 0) == 0, -1); + return 0; +} + +static int SaveServiceBootEvent(int id, const char *name, int argc, const char **argv) +{ + time_t nowTime = time(NULL); + INIT_CHECK_RETURN_VALUE(nowTime > 0, -1); + struct tm *p = localtime(&nowTime); + INIT_CHECK_RETURN_VALUE(p != NULL, -1); + char booteventFileName[BOOT_EVENT_FILEPATH_MAX_LEN] = ""; + INIT_CHECK_RETURN_VALUE(snprintf(booteventFileName, BOOT_EVENT_FILEPATH_MAX_LEN, + BOOTEVENT_OUTPUT_PATH"%d%d%d-%d%d.bootevent", + 1900 + p->tm_year, p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min) >= 0, -1); // 1900 is start year + CheckAndCreatFile(booteventFileName, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); + FILE *tmpFile = fopen(booteventFileName, "wr"); + INIT_CHECK_RETURN_VALUE(tmpFile != NULL, -1); + cJSON *root = cJSON_CreateArray(); + INIT_CHECK_RETURN_VALUE(root != NULL, -1); + OH_ListTraversal(&bootEventList, (void *)root, BooteventTraversal, 0); + char *buff = cJSON_Print(root); + INIT_CHECK_RETURN_VALUE(buff != NULL, -1); + INIT_CHECK_RETURN_VALUE(fprintf(tmpFile, "%s\n", buff) >= 0, -1); + free(buff); + cJSON_Delete(root); + (void)fflush(tmpFile); + (void)fclose(tmpFile); + return 0; +} + static int32_t g_executorId = -1; static int ParamSetBootEventHook(const HOOK_INFO *hookInfo, void *cookie) { if (g_executorId == -1) { g_executorId = AddCmdExecutor("bootevent", DoBootEventCmd); + AddCmdExecutor("save.bootevent", SaveServiceBootEvent); } return 0; } @@ -194,10 +260,12 @@ static void DumpServiceBootEvent(SERVICE_INFO_CTX *serviceCtx) 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, "%ld.%ld", - (long)item->timestamp[BOOTEVENT_FORK].tv_sec, (long)item->timestamp[BOOTEVENT_FORK].tv_nsec) >= 0); - INIT_CHECK_ONLY_RETURN(sprintf_s(booteventReadyTimeStamp, BOOT_EVENT_TIMESTAMP_MAX_LEN, "%ld.%ld", - (long)item->timestamp[BOOTEVENT_READY].tv_sec, (long)item->timestamp[BOOTEVENT_READY].tv_nsec) >= 0); + 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); } diff --git a/services/param/watcher/etc/param_watcher.cfg b/services/param/watcher/etc/param_watcher.cfg index d588f10e..63138d6d 100755 --- a/services/param/watcher/etc/param_watcher.cfg +++ b/services/param/watcher/etc/param_watcher.cfg @@ -5,7 +5,8 @@ "uid" : "paramwatcher", "start-mode" : "boot", "gid" : ["paramwatcher", "shell"], - "secon" : "u:r:param_watcher:s0" + "secon" : "u:r:param_watcher:s0", + "bootevents" : "bootevent.param_watcher.started" } ] } diff --git a/services/param/watcher/proxy/watcher_manager.cpp b/services/param/watcher/proxy/watcher_manager.cpp index bce1fc77..feb94e3a 100644 --- a/services/param/watcher/proxy/watcher_manager.cpp +++ b/services/param/watcher/proxy/watcher_manager.cpp @@ -316,6 +316,7 @@ void WatcherManager::OnStart() if (!res) { WATCHER_LOGE("WatcherManager Publish failed"); } + SystemSetParameter("bootevent.param_watcher.started", "true"); if (deathRecipient_ == nullptr) { deathRecipient_ = new DeathRecipient(this); } diff --git a/test/unittest/init/service_unittest.cpp b/test/unittest/init/service_unittest.cpp index 39c09323..9365422e 100644 --- a/test/unittest/init/service_unittest.cpp +++ b/test/unittest/init/service_unittest.cpp @@ -261,35 +261,56 @@ HWTEST_F(ServiceUnitTest, TestServiceManagerGetService, TestSize.Level1) ret = ParseOneService(serviceItem, service); EXPECT_NE(ret, 0); } + +/** +* @tc.name: TestServiceBootEventHook +* @tc.desc: test bootevent module exec correct +* @tc.type: FUNC +* @tc.require: issueI5NTX4 +* @tc.author: +*/ HWTEST_F(ServiceUnitTest, TestServiceBootEventHook, TestSize.Level1) { - Service *service = nullptr; - const char *jsonStr = "{\"services\":{\"name\":\"test_service8\",\"path\":[\"/data/init_ut/test_service\"]," - "\"importance\":-20,\"uid\":\"system\",\"writepid\":[\"/dev/test_service\"],\"console\":1," - "\"bootevents\" : [\"bootevent1\", \"bootevent2\"]," - "\"gid\":[\"system\"], \"critical\":[1,2]}}"; - cJSON* jobItem = cJSON_Parse(jsonStr); - ASSERT_NE(nullptr, jobItem); - cJSON *serviceItem = cJSON_GetObjectItem(jobItem, "services"); - ASSERT_NE(nullptr, serviceItem); - service = AddService("test_service2"); - ASSERT_NE(nullptr, service); - int ret = ParseOneService(serviceItem, service); - if (ret < 0) { - return; - } + const char *serviceStr = "{" + "\"services\": [{" + "\"name\" : \"test-service\"," + "\"path\" : [\"/dev/test_service\"]," + "\"start-mode\" : \"condition\"," + "\"writepid\":[\"/dev/test_service\"]," + "\"bootevents\" : \"bootevent2\"" + "},{" + "\"name\" : \"test-service\"," + "\"path\" : [\"/dev/test_service\"]," + "\"start-mode\" : \"condition\"," + "\"writepid\":[\"/dev/test_service\"]," + "\"bootevents\" : \"bootevent.bootevent2\"" + "},{" + "\"name\" : \"test-service2\"," + "\"path\" : [\"/dev/test_service\"]," + "\"console\":1," + "\"start-mode\" : \"boot\"," + "\"writepid\":[\"/dev/test_service\"]," + "\"bootevents\" : [\"bootevent.bootevent1\", \"bootevent.bootevent2\"]" + "}]" + "}"; - SERVICE_PARSE_CTX context; - context.serviceName = "test_service2"; - context.serviceNode = serviceItem; - (void)HookMgrExecute(GetBootStageHookMgr(), INIT_SERVICE_PARSE, (void *)(&context), NULL); - ASSERT_NE(GetServiceExtData("test_service2", HOOK_ID_BOOTEVENT), nullptr); SERVICE_INFO_CTX serviceInfoContext; - serviceInfoContext.serviceName = "test_service2"; - serviceInfoContext.reserved = nullptr; + serviceInfoContext.serviceName = "test-service2"; + 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); + ParseAllServices(fileRoot); (void)HookMgrExecute(GetBootStageHookMgr(), INIT_SERVICE_FORK_BEFORE, (void *)(&serviceInfoContext), NULL); + SystemWriteParam("bootevent.bootevent1", "true"); + SystemWriteParam("bootevent.bootevent1", "true"); + SystemWriteParam("bootevent.bootevent2", "true"); + SystemSetParameter("ohos.servicectrl.save.bootevent", "save.bootevent"); (void)HookMgrExecute(GetBootStageHookMgr(), INIT_SERVICE_DUMP, (void *)(&serviceInfoContext), NULL); (void)HookMgrExecute(GetBootStageHookMgr(), INIT_SERVICE_CLEAR, (void *)(&serviceInfoContext), NULL); + cJSON_Delete(fileRoot); } HWTEST_F(ServiceUnitTest, TestServiceExec, TestSize.Level1) -- GitLab