From 83d6df467bf149cd2587f17c7573006f422dd0bd Mon Sep 17 00:00:00 2001 From: cheng_jinsong Date: Thu, 20 Apr 2023 14:50:58 +0800 Subject: [PATCH] add init trace Signed-off-by: cheng_jinsong --- services/etc/init.cfg | 9 +- services/modules/BUILD.gn | 7 +- services/modules/bootevent/bootevent.c | 9 +- services/modules/init_hook/init_hook.c | 10 + services/modules/init_hook/param_hook.c | 3 + services/modules/plugin_adapter.h | 7 +- services/modules/trace/BUILD.gn | 63 +++ services/modules/trace/init_trace.c | 575 ++++++++++++++++++++ services/modules/trace/init_trace.cfg | 596 +++++++++++++++++++++ services/modules/trace/init_trace_static.c | 35 ++ services/param/manager/param_manager.c | 2 +- test/unittest/BUILD.gn | 8 + test/unittest/modules/trace_unittest.cpp | 160 ++++++ 13 files changed, 1474 insertions(+), 10 deletions(-) create mode 100644 services/modules/trace/BUILD.gn create mode 100644 services/modules/trace/init_trace.c create mode 100644 services/modules/trace/init_trace.cfg create mode 100644 services/modules/trace/init_trace_static.c create mode 100644 test/unittest/modules/trace_unittest.cpp diff --git a/services/etc/init.cfg b/services/etc/init.cfg index f1c79421..eb843118 100755 --- a/services/etc/init.cfg +++ b/services/etc/init.cfg @@ -26,7 +26,9 @@ "load_persist_params ", "bootchart start", "chown access_token access_token /dev/access_token_id", - "chmod 0666 /dev/access_token_id" + "chmod 0666 /dev/access_token_id", + "trigger init-hitrace", + "trigger init-trace" ] }, { "name" : "init", @@ -191,6 +193,11 @@ "chmod 0773 /data/misc/trace", "chmod 0775 /data/misc/wmtrace" ] + }, { + "name" : "init-trace", + "cmds" : [ + "init_trace start" + ] } ] } diff --git a/services/modules/BUILD.gn b/services/modules/BUILD.gn index 51dabe84..a693484b 100755 --- a/services/modules/BUILD.gn +++ b/services/modules/BUILD.gn @@ -1,4 +1,4 @@ -# Copyright (c) 2020-2022 Huawei Device Co., Ltd. +# Copyright (c) 2023 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 @@ -27,6 +27,10 @@ group("static_modules") { if (build_selinux) { deps += [ "selinux:libselinuxadp_static" ] } + deps += [ + "trace:inittrace_cfg", + "trace:libinittrace_static", + ] } } @@ -35,6 +39,7 @@ group("modulesgroup") { deps = [ "bootchart:bootchart", "reboot:rebootmodule", + "trace:inittrace", "udid:udidmodule", ] if (build_seccomp) { diff --git a/services/modules/bootevent/bootevent.c b/services/modules/bootevent/bootevent.c index 587619ba..b7f7daee 100755 --- a/services/modules/bootevent/bootevent.c +++ b/services/modules/bootevent/bootevent.c @@ -189,7 +189,7 @@ static int BootEventTraversal(ListNode *node, void *root) static int SaveServiceBootEvent() { - if (g_bootEventEnable == 0) { + if (!GetBootEventEnable()) { return 0; } time_t nowTime = time(NULL); @@ -408,13 +408,13 @@ static void SetServiceBootEventFork(SERVICE_INFO_CTX *serviceCtx) return; } -static int GetBootEventFlag(const HOOK_INFO *info, void *cookie) +int GetBootEventEnable(void) { 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; + if (strcmp(bootEventOpen, "true") == 0 || strcmp(bootEventOpen, "1") == 0) { + return 1; } return 0; } @@ -435,5 +435,4 @@ MODULE_CONSTRUCTOR(void) InitAddClearServiceHook(ClearServiceBootEvent); InitAddServiceParseHook(ServiceParseBootEventHook); InitAddGlobalInitHook(0, ParamSetBootEventHook); - InitAddPostPersistParamLoadHook(0, GetBootEventFlag); } diff --git a/services/modules/init_hook/init_hook.c b/services/modules/init_hook/init_hook.c index 16505746..5548c10e 100755 --- a/services/modules/init_hook/init_hook.c +++ b/services/modules/init_hook/init_hook.c @@ -245,6 +245,10 @@ static int BootCompleteCmd(const HOOK_INFO *hookInfo, void *executionContext) HookMgrDel(GetBootStageHookMgr(), INIT_JOB_PARSE, NULL); // clear cmd RemoveCmdExecutor("loadSelinuxPolicy", -1); + + PluginExecCmdByName("init_trace", "stop"); + // uninstall module of inittrace + InitModuleMgrUnInstall("inittrace"); return 0; } @@ -255,3 +259,9 @@ MODULE_CONSTRUCTOR(void) // Depends on parameter service InitAddPostPersistParamLoadHook(0, InitDebugHook); } + +MODULE_DESTRUCTOR(void) +{ + const char *clearBootEventArgv[] = {"bootevent"}; + PluginExecCmd("clear", ARRAY_LENGTH(clearBootEventArgv), clearBootEventArgv); +} diff --git a/services/modules/init_hook/param_hook.c b/services/modules/init_hook/param_hook.c index cd5cb2b5..5587ee46 100755 --- a/services/modules/init_hook/param_hook.c +++ b/services/modules/init_hook/param_hook.c @@ -65,6 +65,7 @@ const ParamCmdInfo *GetServiceCtl(size_t *size) {"ohos.servicectrl.uninstall", "uninstall", "uninstall" }, {"ohos.servicectrl.clear", "clear", "clear" }, {"ohos.servicectrl.bootchart", "bootchart", "bootchart" }, + {"ohos.servicectrl.init_trace", "init_trace", "init_trace" }, {"ohos.servicectrl.timer_start", "timer_start", "timer_start " }, {"ohos.servicectrl.timer_stop", "timer_stop", "timer_stop" }, {"ohos.servicectrl.cmd", "cmd", "initcmd"}, @@ -93,6 +94,8 @@ const ParamCmdInfo *GetOtherSpecial(size_t *size) static const ParamCmdInfo other[] = { {"bootevent.", "bootevent.", "bootevent"}, {"persist.init.debug.", "persist.init.debug.", "setloglevel"}, + // for hitrace start, need interrupt init trace + {"debug.hitrace.enable.state", "debug.hitrace.enable.state.", "init_trace"}, }; *size = ARRAY_LENGTH(other); return other; diff --git a/services/modules/plugin_adapter.h b/services/modules/plugin_adapter.h index 4e70af2a..d7d545dd 100755 --- a/services/modules/plugin_adapter.h +++ b/services/modules/plugin_adapter.h @@ -35,15 +35,16 @@ #define PLUGIN_LOGI(fmt, ...) STARTUP_LOGI(PLUGIN_DOMAIN, PLUGIN_LABEL, fmt, ##__VA_ARGS__) #define PLUGIN_LOGE(fmt, ...) STARTUP_LOGE(PLUGIN_DOMAIN, PLUGIN_LABEL, fmt, ##__VA_ARGS__) #define PLUGIN_LOGV(fmt, ...) STARTUP_LOGV(PLUGIN_DOMAIN, PLUGIN_LABEL, fmt, ##__VA_ARGS__) +#define PLUGIN_LOGW(fmt, ...) STARTUP_LOGW(PLUGIN_DOMAIN, PLUGIN_LABEL, fmt, ##__VA_ARGS__) #define PLUGIN_CHECK(ret, exper, ...) \ if (!(ret)) { \ PLUGIN_LOGE(__VA_ARGS__); \ exper; \ } -#define PLUGIN_ONLY_CHECK(ret, exper, ...) \ +#define PLUGIN_ONLY_LOG(ret, ...) \ if (!(ret)) { \ - exper; \ + PLUGIN_LOGE(__VA_ARGS__); \ } #define HOOKID(name) HOOK_ID_##name @@ -53,4 +54,6 @@ enum HOOK_ID_ { HOOKID(BOOTEVENT), HOOKID(BOOTEVENT_MAX) = HOOK_ID_BOOTEVENT + 10, }; + +int GetBootEventEnable(void); #endif diff --git a/services/modules/trace/BUILD.gn b/services/modules/trace/BUILD.gn new file mode 100644 index 00000000..6f40bdc4 --- /dev/null +++ b/services/modules/trace/BUILD.gn @@ -0,0 +1,63 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import("//base/startup/init/begetd.gni") +import("//build/ohos.gni") + +comm_include = [ + ".", + "..", + "../../include", + "../../include/param", +] + +ohos_shared_library("inittrace") { + sources = [ "init_trace.c" ] + + include_dirs = comm_include + include_dirs += [ "//third_party/zlib" ] + + deps = [ + "//third_party/bounds_checking_function:libsec_shared", + "//third_party/cJSON:cjson", + "//third_party/zlib:libz", + ] + + external_deps = [ "init:libinit_module_engine" ] + + part_name = "init" + subsystem_name = "startup" + if (target_cpu == "arm64") { + module_install_dir = "lib64/init" + } else { + module_install_dir = "lib/init" + } +} + +config("inittrace_static_config") { + include_dirs = comm_include +} + +ohos_prebuilt_etc("inittrace_cfg") { + source = "init_trace.cfg" + part_name = "init" + subsystem_name = "startup" +} + +ohos_source_set("libinittrace_static") { + sources = [ "init_trace_static.c" ] + include_dirs = comm_include + public_configs = [ ":inittrace_static_config" ] + public_configs += [ "../../../interfaces/innerkits/init_module_engine:init_module_engine_exported_config" ] + part_name = "init" + subsystem_name = "startup" +} diff --git a/services/modules/trace/init_trace.c b/services/modules/trace/init_trace.c new file mode 100644 index 00000000..ac49f524 --- /dev/null +++ b/services/modules/trace/init_trace.c @@ -0,0 +1,575 @@ +/* + * Copyright (C) 2023 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "cJSON.h" +#include "init_module_engine.h" +#include "init_param.h" +#include "init_utils.h" +#include "plugin_adapter.h" +#include "securec.h" + +#define MAX_SYS_FILES 11 +#define CHUNK_SIZE 65536 +#define BLOCK_SIZE 4096 +#define WAIT_MILLISECONDS 10 +#define BUFFER_SIZE_KB 10240 // 10M + +#define TRACE_CFG_KERNEL "KERNEL" +#define TRACE_CFG_USER "USER" +#define TRACE_TAG_PARAMETER "debug.hitrace.tags.enableflags" +#define TRACE_DEBUG_FS_PATH "/sys/kernel/debug/tracing/" +#define TRACE_FS_PATH "/sys/kernel/tracing/" +#define TRACE_CFG_PATH STARTUP_INIT_UT_PATH"/system/etc/init_trace.cfg" +#define TRACE_OUTPUT_PATH "/data/service/el0/startup/init/init_trace.log" +#define TRACE_OUTPUT_PATH_ZIP "/data/service/el0/startup/init/init_trace.zip" + +#define TRACE_CMD "ohos.servicectrl.init_trace" + +// various operating paths of ftrace +#define TRACING_ON_PATH "tracing_on" +#define TRACE_PATH "trace" +#define TRACE_MARKER_PATH "trace_marker" +#define TRACE_CURRENT_TRACER "current_tracer" +#define TRACE_BUFFER_SIZE_KB "buffer_size_kb" +#define TRACE_CLOCK "trace_clock" +#define TRACE_DEF_CLOCK "boot" + +typedef enum { + TRACE_STATE_IDLE, + TRACE_STATE_STARTED, + TRACE_STATE_STOPED, + TRACE_STATE_INTERRUPT +} TraceState; + +typedef struct { + char *traceRootPath; + char buffer[PATH_MAX]; + cJSON *jsonRootNode; + TraceState traceState; + uint32_t compress : 1; +} TraceWorkspace; + +static TraceWorkspace g_traceWorkspace = {NULL, {0}, NULL, 0, 0}; +static TraceWorkspace *GetTraceWorkspace(void) +{ + return &g_traceWorkspace; +} + +static char *ReadFile(const char *path) +{ + struct stat fileStat = {0}; + if (stat(path, &fileStat) != 0 || fileStat.st_size <= 0) { + PLUGIN_LOGE("Invalid file %s or buffer %zu", path, fileStat.st_size); + return NULL; + } + FILE *fd = fopen(path, "r"); + PLUGIN_CHECK(fd != NULL, return NULL, "Failed to fopen path %s", path); + char *buffer = NULL; + do { + buffer = (char*)malloc((size_t)(fileStat.st_size + 1)); + PLUGIN_CHECK(buffer != NULL, break, "Failed to alloc memory for path %s", path); + if (fread(buffer, fileStat.st_size, 1, fd) != 1) { + PLUGIN_LOGE("Failed to read file %s errno:%d", path, errno); + free(buffer); + buffer = NULL; + } else { + buffer[fileStat.st_size] = '\0'; + } + } while (0); + (void)fclose(fd); + return buffer; +} + +static int InitTraceWorkspace(TraceWorkspace *workspace) +{ + workspace->traceRootPath = NULL; + workspace->traceState = TRACE_STATE_IDLE; + workspace->compress = 0; + char *fileBuf = ReadFile(TRACE_CFG_PATH); + PLUGIN_CHECK(fileBuf != NULL, return -1, "Failed to read file content %s", TRACE_CFG_PATH); + workspace->jsonRootNode = cJSON_Parse(fileBuf); + PLUGIN_CHECK(workspace->jsonRootNode != NULL, free(fileBuf); + return -1, "Failed to parse json file %s", TRACE_CFG_PATH); + workspace->compress = cJSON_IsTrue(cJSON_GetObjectItem(workspace->jsonRootNode, "compress")) ? 1 : 0; + PLUGIN_LOGI("InitTraceWorkspace compress :%d", workspace->compress); + free(fileBuf); + return 0; +} + +static void DestroyTraceWorkspace(TraceWorkspace *workspace) +{ + if (workspace->traceRootPath) { + free(workspace->traceRootPath); + workspace->traceRootPath = NULL; + } + if (workspace->jsonRootNode) { + cJSON_Delete(workspace->jsonRootNode); + workspace->jsonRootNode = NULL; + } + workspace->traceState = TRACE_STATE_IDLE; +} + +static bool IsTraceMountedInner(TraceWorkspace *workspace, const char *fsPath) +{ + int len = sprintf_s((char *)workspace->buffer, sizeof(workspace->buffer), + "%s%s", fsPath, TRACE_MARKER_PATH); + PLUGIN_CHECK(len > 0, return false, "Failed to format path %s", fsPath); + if (access(workspace->buffer, F_OK) != -1) { + workspace->traceRootPath = strdup(fsPath); + return true; + } + return false; +} + +static bool IsTraceMounted(TraceWorkspace *workspace) +{ + return IsTraceMountedInner(workspace, TRACE_DEBUG_FS_PATH) || + IsTraceMountedInner(workspace, TRACE_FS_PATH); +} + +static bool IsWritableFile(const char *filename) +{ + TraceWorkspace *workspace = GetTraceWorkspace(); + PLUGIN_CHECK(workspace != NULL, return false, "Failed to get trace workspace"); + int len = sprintf_s((char *)workspace->buffer, sizeof(workspace->buffer), + "%s%s", workspace->traceRootPath, filename); + PLUGIN_CHECK(len > 0, return false, "Failed to format path %s", filename); + return access(workspace->buffer, W_OK) != -1; +} + +static bool WriteStrToFile(const char *filename, const char *str) +{ + PLUGIN_LOGV("WriteStrToFile filename %s %s", filename, str); + TraceWorkspace *workspace = GetTraceWorkspace(); + PLUGIN_CHECK(workspace != NULL, return false, "Failed to get trace workspace"); + int len = sprintf_s((char *)workspace->buffer, sizeof(workspace->buffer), + "%s%s", workspace->traceRootPath, filename); + PLUGIN_CHECK(len > 0, return false, "Failed to format path %s", filename); + FILE *outfile = fopen(workspace->buffer, "w"); + PLUGIN_CHECK(outfile != NULL, return false, "Failed to open file %s.", workspace->buffer); + (void)fprintf(outfile, "%s", str); + (void)fflush(outfile); + (void)fclose(outfile); + return true; +} + +static bool SetTraceEnabled(const char *path, bool enabled) +{ + return WriteStrToFile(path, enabled ? "1" : "0"); +} + +static bool SetBufferSize(int bufferSize) +{ + if (!WriteStrToFile(TRACE_CURRENT_TRACER, "nop")) { + PLUGIN_LOGE("%s", "Error: write \"nop\" to %s\n", TRACE_CURRENT_TRACER); + } + char buffer[20] = {0}; // 20 max int number + int len = sprintf_s((char *)buffer, sizeof(buffer), "%d", bufferSize); + PLUGIN_CHECK(len > 0, return false, "Failed to format int %d", bufferSize); + PLUGIN_LOGE("SetBufferSize path %s %s", TRACE_BUFFER_SIZE_KB, buffer); + return WriteStrToFile(TRACE_BUFFER_SIZE_KB, buffer); +} + +static bool SetClock(const char *timeClock) +{ + return WriteStrToFile(TRACE_CLOCK, timeClock); +} + +static bool SetOverWriteEnable(bool enabled) +{ + return SetTraceEnabled("options/overwrite", enabled); +} + +static bool SetTgidEnable(bool enabled) +{ + return SetTraceEnabled("options/record-tgid", enabled); +} + +static bool SetTraceTagsEnabled(uint64_t tags) +{ + TraceWorkspace *workspace = GetTraceWorkspace(); + PLUGIN_CHECK(workspace != NULL, return false, "Failed to get trace workspace"); + int len = sprintf_s((char *)workspace->buffer, sizeof(workspace->buffer), "%" PRId64 "", tags); + PLUGIN_CHECK(len > 0, return false, "Failed to format tags %" PRId64 "", tags); + return SystemWriteParam(TRACE_TAG_PARAMETER, workspace->buffer) == 0; +} + +static bool RefreshServices() +{ + return true; +} + +static cJSON *GetArrayItem(const cJSON *fileRoot, int *arrSize, const char *arrName) +{ + cJSON *arrItem = cJSON_GetObjectItemCaseSensitive(fileRoot, arrName); + if (!cJSON_IsArray(arrItem)) { + return NULL; + } + *arrSize = cJSON_GetArraySize(arrItem); + return *arrSize > 0 ? arrItem : NULL; +} + +static bool SetUserSpaceSettings(void) +{ + TraceWorkspace *workspace = GetTraceWorkspace(); + PLUGIN_CHECK(workspace != NULL, return false, "Failed to get trace workspace"); + int size = 0; + cJSON *userItem = GetArrayItem(workspace->jsonRootNode, &size, TRACE_CFG_USER); + PLUGIN_CHECK(userItem != NULL, return false, "Failed to get user info"); + + PLUGIN_LOGI("SetUserSpaceSettings: %d", size); + uint64_t enabledTags = 0; + for (int i = 0; i < size; i++) { + cJSON *item = cJSON_GetArrayItem(userItem, i); + PLUGIN_LOGI("Tag name = %s ", cJSON_GetStringValue(cJSON_GetObjectItem(item, "name"))); + int tag = cJSON_GetNumberValue(cJSON_GetObjectItem(item, "tag")); + enabledTags |= 1ULL << tag; + } + PLUGIN_LOGI("User enabledTags: %" PRId64 "", enabledTags); + return SetTraceTagsEnabled(enabledTags) && RefreshServices(); +} + +static bool ClearUserSpaceSettings(void) +{ + return SetTraceTagsEnabled(0) && RefreshServices(); +} + +static bool SetKernelTraceEnabled(const TraceWorkspace *workspace, bool enabled) +{ + bool result = true; + PLUGIN_LOGI("SetKernelTraceEnabled %s", enabled ? "enable" : "disable"); + int size = 0; + cJSON *kernelItem = GetArrayItem(workspace->jsonRootNode, &size, TRACE_CFG_KERNEL); + PLUGIN_CHECK(kernelItem != NULL, return false, "Failed to get user info"); + for (int i = 0; i < size; i++) { + cJSON *tagJson = cJSON_GetArrayItem(kernelItem, i); + const char *name = cJSON_GetStringValue(cJSON_GetObjectItem(tagJson, "name")); + int pathCount = 0; + cJSON *paths = GetArrayItem(tagJson, &pathCount, "sys-files"); + if (paths == NULL) { + continue; + } + PLUGIN_LOGV("Kernel tag name: %s sys-files %d", name, pathCount); + for (int j = 0; j < pathCount; j++) { + char *path = cJSON_GetStringValue(cJSON_GetArrayItem(paths, j)); + if (path == NULL) { + continue; + } + if (!IsWritableFile(path)) { + PLUGIN_LOGW("Path %s is not writable for %s", path, name); + continue; + } + result = result && SetTraceEnabled(path, enabled); + } + } + return result; +} + +static bool DisableAllTraceEvents(void) +{ + TraceWorkspace *workspace = GetTraceWorkspace(); + PLUGIN_CHECK(workspace != NULL, return false, "Failed to get trace workspace"); + return SetKernelTraceEnabled(workspace, false); +} + +static bool SetKernelSpaceSettings(void) +{ + TraceWorkspace *workspace = GetTraceWorkspace(); + PLUGIN_CHECK(workspace != NULL, return false, "Failed to get trace workspace"); + bool ret = SetBufferSize(BUFFER_SIZE_KB); + PLUGIN_CHECK(ret, return false, "Failed to set buffer"); + ret = SetClock(TRACE_DEF_CLOCK); + PLUGIN_CHECK(ret, return false, "Failed to set clock"); + ret = SetOverWriteEnable(true); + PLUGIN_CHECK(ret, return false, "Failed to set write enable"); + ret = SetTgidEnable(true); + PLUGIN_CHECK(ret, return false, "Failed to set tgid enable"); + ret = SetKernelTraceEnabled(workspace, false); + PLUGIN_CHECK(ret, return false, "Pre-clear kernel tracers failed"); + return SetKernelTraceEnabled(workspace, true); +} + +static bool ClearKernelSpaceSettings(void) +{ + return DisableAllTraceEvents() && SetOverWriteEnable(true) && SetBufferSize(1) && SetClock("boot"); +} + +static bool ClearTrace(void) +{ + TraceWorkspace *workspace = GetTraceWorkspace(); + PLUGIN_CHECK(workspace != NULL, return false, "Failed to get trace workspace"); + + int len = sprintf_s((char *)workspace->buffer, sizeof(workspace->buffer), + "%s%s", workspace->traceRootPath, TRACE_PATH); + PLUGIN_CHECK(len > 0, return false, "Failed to format path %s", TRACE_PATH); + // clear old trace file + int fd = open(workspace->buffer, O_RDWR); + PLUGIN_CHECK(fd >= 0, return false, "Failed to open file %s errno %d", workspace->buffer, errno); + (void)ftruncate(fd, 0); + close(fd); + return true; +} + +static void DumpCompressedTrace(int traceFd, int outFd) +{ + int flush = Z_NO_FLUSH; + uint8_t *inBuffer = malloc(CHUNK_SIZE); + PLUGIN_CHECK(inBuffer != NULL, return, "Error: couldn't allocate buffers\n"); + uint8_t *outBuffer = malloc(CHUNK_SIZE); + PLUGIN_CHECK(outBuffer != NULL, free(inBuffer); + return, "Error: couldn't allocate buffers\n"); + + z_stream zs = {}; + int ret = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, MAX_WBITS + 16, 8, Z_DEFAULT_STRATEGY); // 16 8 bit + do { + // read data + zs.avail_in = TEMP_FAILURE_RETRY(read(traceFd, inBuffer, CHUNK_SIZE)); + PLUGIN_CHECK(zs.avail_in >= 0, break, "Error: reading trace, errno: %d\n", errno); + flush = zs.avail_in == 0 ? Z_FINISH : Z_NO_FLUSH; + zs.next_in = inBuffer; + do { + zs.next_out = outBuffer; + zs.avail_out = CHUNK_SIZE; + ret = deflate(&zs, flush); + PLUGIN_CHECK(ret != Z_STREAM_ERROR, break, "Error: deflate trace, errno: %d\n", errno); + size_t have = CHUNK_SIZE - zs.avail_out; + size_t bytesWritten = TEMP_FAILURE_RETRY(write(outFd, outBuffer, have)); + if (bytesWritten < have) { + PLUGIN_LOGE("Error: writing deflated trace, errno: %d\n", errno); + flush = Z_FINISH; // finish + break; + } + } while (zs.avail_out == 0); + } while (flush != Z_FINISH); + + ret = deflateEnd(&zs); + PLUGIN_ONLY_LOG(ret == Z_OK, "error cleaning up zlib: %d\n", ret); + free(inBuffer); + free(outBuffer); +} + +static void DumpTrace(const TraceWorkspace *workspace, int outFd, const char *path) +{ + int len = sprintf_s((char *)workspace->buffer, sizeof(workspace->buffer), "%s%s", workspace->traceRootPath, path); + PLUGIN_CHECK(len > 0, return, "Failed to format path %s", path); + int traceFd = open(workspace->buffer, O_RDWR); + PLUGIN_CHECK(traceFd >= 0, return, "Failed to open file %s errno %d", workspace->buffer, errno); + + ssize_t bytesWritten; + ssize_t bytesRead; + if (workspace->compress) { + DumpCompressedTrace(traceFd, outFd); + } else { + char buffer[BLOCK_SIZE]; + do { + bytesRead = TEMP_FAILURE_RETRY(read(traceFd, buffer, BLOCK_SIZE)); + if ((bytesRead == 0) || (bytesRead == -1)) { + break; + } + bytesWritten = TEMP_FAILURE_RETRY(write(outFd, buffer, bytesRead)); + } while (bytesWritten > 0); + } + close(traceFd); +} + +static bool MarkOthersClockSync(void) +{ + TraceWorkspace *workspace = GetTraceWorkspace(); + PLUGIN_CHECK(workspace != NULL, return false, "Failed to get trace workspace"); + int len = sprintf_s((char *)workspace->buffer, sizeof(workspace->buffer), "%s%s", + workspace->traceRootPath, TRACE_MARKER_PATH); + PLUGIN_CHECK(len > 0, return false, "Failed to format path %s", TRACE_MARKER_PATH); + + struct timespec mts = {0, 0}; + struct timespec rts = {0, 0}; + if (clock_gettime(CLOCK_REALTIME, &rts) == -1) { + PLUGIN_LOGE("Error: get realtime, errno: %d", errno); + return false; + } else if (clock_gettime(CLOCK_MONOTONIC, &mts) == -1) { + PLUGIN_LOGE("Error: get monotonic, errno: %d\n", errno); + return false; + } + const unsigned int nanoSeconds = 1000000000; // seconds converted to nanoseconds + const unsigned int nanoToMill = 1000000; // millisecond converted to nanoseconds + const float nanoToSecond = 1000000000.0f; // consistent with the ftrace timestamp format + + PLUGIN_LOGE("MarkOthersClockSync %s", workspace->buffer); + FILE *file = fopen(workspace->buffer, "wt+"); + PLUGIN_CHECK(file != NULL, return false, "Error: opening %s, errno: %d", TRACE_MARKER_PATH, errno); + do { + int64_t realtime = (int64_t)((rts.tv_sec * nanoSeconds + rts.tv_nsec) / nanoToMill); + float parentTs = (float)((((float)mts.tv_sec) * nanoSeconds + mts.tv_nsec) / nanoToSecond); + int ret = fprintf(file, "trace_event_clock_sync: realtime_ts=%" PRId64 "\n", realtime); + PLUGIN_CHECK(len > 0, break, "Warning: writing clock sync marker, errno: %d", errno); + ret = fprintf(file, "trace_event_clock_sync: parent_ts=%f\n", parentTs); + PLUGIN_CHECK(len > 0, break, "Warning: writing clock sync marker, errno: %d", errno); + } while (0); + (void)fclose(file); + return true; +} + +static int InitStartTrace(void) +{ + TraceWorkspace *workspace = GetTraceWorkspace(); + PLUGIN_CHECK(workspace != NULL, return 0, "Failed to get trace workspace"); + if (workspace->traceState != TRACE_STATE_IDLE) { + PLUGIN_LOGE("Invalid state for trace %d", workspace->traceState); + return 0; + } + InitTraceWorkspace(workspace); + if (!IsTraceMounted(workspace)) { + return -1; + } + PLUGIN_CHECK(workspace->traceRootPath != NULL && workspace->jsonRootNode != NULL, + return -1, "No trace root path or config"); + + // load json init_trace.cfg + if (!SetKernelSpaceSettings()) { + PLUGIN_LOGE("Failed to enable kernel space setting"); + ClearKernelSpaceSettings(); + return -1; + } + + if (!SetTraceEnabled(TRACING_ON_PATH, true)) { + PLUGIN_LOGE("Failed to enable trace"); + ClearKernelSpaceSettings(); + return -1; + } + ClearTrace(); + PLUGIN_LOGI("capturing trace..."); + if (!SetUserSpaceSettings()) { + PLUGIN_LOGE("Failed to enable user space setting"); + ClearKernelSpaceSettings(); + ClearUserSpaceSettings(); + return -1; + } + workspace->traceState = TRACE_STATE_STARTED; + return 0; +} + +static int InitStopTrace(void) +{ + PLUGIN_LOGI("Stop trace now ..."); + TraceWorkspace *workspace = GetTraceWorkspace(); + PLUGIN_CHECK(workspace != NULL, return 0, "Failed to get trace workspace"); + if (workspace->traceState != TRACE_STATE_STARTED) { + PLUGIN_LOGE("Invalid state for trace %d", workspace->traceState); + return 0; + } + workspace->traceState = TRACE_STATE_STOPED; + + MarkOthersClockSync(); + // clear user tags first and sleep a little to let apps already be notified. + ClearUserSpaceSettings(); + usleep(WAIT_MILLISECONDS); + SetTraceEnabled(TRACING_ON_PATH, false); + + const char *path = workspace->compress ? TRACE_OUTPUT_PATH_ZIP : TRACE_OUTPUT_PATH; + int outFd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (outFd >= 0) { + DumpTrace(workspace, outFd, TRACE_PATH); + close(outFd); + } else { + PLUGIN_LOGE("Failed to open file '%s', err=%d", path, errno); + } + + ClearTrace(); + // clear kernel setting including clock type after dump(MUST) and tracing_on is off. + ClearKernelSpaceSettings(); + // init hitrace config + DoJobNow("init-hitrace"); + DestroyTraceWorkspace(workspace); + return 0; +} + +static int InitInterruptTrace(void) +{ + PLUGIN_LOGI("Interrupt trace now ..."); + TraceWorkspace *workspace = GetTraceWorkspace(); + PLUGIN_CHECK(workspace != NULL, return 0, "Failed to get trace workspace"); + if (workspace->traceState != TRACE_STATE_STARTED) { + PLUGIN_LOGE("Invalid state for trace %d", workspace->traceState); + return 0; + } + workspace->traceState = TRACE_STATE_INTERRUPT; + MarkOthersClockSync(); + // clear user tags first and sleep a little to let apps already be notified. + ClearUserSpaceSettings(); + SetTraceEnabled(TRACING_ON_PATH, false); + ClearTrace(); + // clear kernel setting including clock type after dump(MUST) and tracing_on is off. + ClearKernelSpaceSettings(); + // init hitrace config + DoJobNow("init-hitrace"); + DestroyTraceWorkspace(workspace); + return 0; +} + +static int DoInitTraceCmd(int id, const char *name, int argc, const char **argv) +{ + PLUGIN_CHECK(argc >= 1, return -1, "Invalid parameter"); + PLUGIN_LOGI("DoInitTraceCmd argc %d cmd %s", argc, argv[0]); + if (strcmp(argv[0], "start") == 0) { + return InitStartTrace(); + } else if (strcmp(argv[0], "stop") == 0) { + return InitStopTrace(); + } else if (strcmp(argv[0], "1") == 0) { + return InitInterruptTrace(); + } + return 0; +} + +static int g_executorId = -1; +static int InitTraceInit(void) +{ + if (g_executorId == -1) { + g_executorId = AddCmdExecutor("init_trace", DoInitTraceCmd); + PLUGIN_LOGI("InitTraceInit executorId %d", g_executorId); + } + return 0; +} + +static void InitTraceExit(void) +{ + PLUGIN_LOGI("InitTraceExit executorId %d", g_executorId); + if (g_executorId != -1) { + RemoveCmdExecutor("init_trace", g_executorId); + } +} + +MODULE_CONSTRUCTOR(void) +{ + PLUGIN_LOGI("Start trace now ..."); + InitTraceInit(); +} + +MODULE_DESTRUCTOR(void) +{ + InitTraceExit(); +} diff --git a/services/modules/trace/init_trace.cfg b/services/modules/trace/init_trace.cfg new file mode 100644 index 00000000..7ca8c429 --- /dev/null +++ b/services/modules/trace/init_trace.cfg @@ -0,0 +1,596 @@ +{ + "compress" : false, + "KERNEL" : [ + { + "name" : "disk", + "description" : "Disk I/O", + "tag" : 0, + "type" : "KERNEL", + "sys-files" : [ + "events/f2fs/f2fs_sync_file_enter/enable", + "events/f2fs/f2fs_sync_file_exit/enable", + "events/f2fs/f2fs_write_begin/enable", + "events/f2fs/f2fs_write_end/enable", + "events/ext4/ext4_da_write_begin/enable", + "events/ext4/ext4_da_write_end/enable", + "events/ext4/ext4_sync_file_enter/enable", + "events/ext4/ext4_sync_file_exit/enable", + "events/block/block_rq_issue/enable", + "events/block/block_rq_complete/enable" + ] + }, + { + "name" : "mmc", + "description" : "eMMC commands", + "tag" : 0, + "type" : "KERNEL", + "sys-files" : [ + "events/mmc/enable" + ] + }, + { + "name" : "zbinder", + "description" : "OpenHarmony binder communication", + "tag" : 0, + "type" : "KERNEL", + "sys-files" : [ + "events/zbinder/enable" + ] + }, + { + "name" : "ufs", + "description" : "UFS commands", + "tag" : 0, + "type" : "KERNEL", + "sys-files" : [ + "events/ufs/enable" + ] + }, + { + "name" : "irq", + "description" : "IRQ Events", + "tag" : 0, + "type" : "KERNEL", + "sys-files" : [ + "events/irq/enable", + "events/ipi/enable" + ] + }, + { + "name" : "irqoff", + "description" : "IRQ-disabled code section tracing", + "tag" : 0, + "type" : "KERNEL", + "sys-files" : [ + "events/preemptirq/irq_enable/enable", + "events/preemptirq/irq_disable/enable" + ] + }, + { + "name" : "i2c", + "description" : "I2C Events", + "tag" : 0, + "type" : "KERNEL", + "sys-files" : [ + "events/i2c/enable" , + "events/i2c/i2c_read/enable" , + "events/i2c/i2c_write/enable" , + "events/i2c/i2c_result/enable" , + "events/i2c/i2c_reply/enable" , + "events/i2c/smbus_read/enable" , + "events/i2c/smbus_write/enable" , + "events/i2c/smbus_result/enable" , + "events/i2c/smbus_reply/enable" + ] + }, + { + "name" : "regulators", + "description" : "Voltage and Current Regulators", + "tag" : 0, + "type" : "KERNEL", + "sys-files" : [ + "events/regulator/enable" + ] + }, + { + "name" : "membus", + "description" : "Memory Bus Utilization", + "tag" : 0, + "type" : "KERNEL", + "sys-files" : [ + "events/memory_bus/enable" + ] + }, + { + "name" : "freq", + "description" : "CPU Frequency", + "tag" : 0, + "type" : "KERNEL", + "sys-files" : [ + "events/power/cpu_frequency/enable", + "events/power/clock_set_rate/enable", + "events/power/clock_disable/enable", + "events/power/clock_enable/enable", + "events/clk/clk_set_rate/enable", + "events/clk/clk_disable/enable", + "events/clk/clk_enable/enable", + "events/power/cpu_frequency_limits/enable" + ] + }, + { + "name" : "idle", + "description" : "CPU Idle", + "tag" : 0, + "type" : "KERNEL", + "sys-files" : [ + "events/power/cpu_idle/enable" + ] + }, + { + "name" : "load", + "description" : "CPU Load", + "tag" : 0, + "type" : "KERNEL", + "sys-files" : [ + "events/cpufreq_interactive/enable" + ] + }, + { + "name" : "sched", + "description" : "CPU Scheduling", + "tag" : 0, + "type" : "KERNEL", + "sys-files" : [ + "events/sched/sched_switch/enable", + "events/sched/sched_wakeup/enable", + "events/sched/sched_wakeup_new/enable", + "events/sched/sched_waking/enable", + "events/sched/sched_blocked_reason/enable", + "events/sched/sched_pi_setprio/enable", + "events/sched/sched_process_exit/enable", + "events/cgroup/enable", + "events/oom/oom_score_adj_update/enable", + "events/task/task_rename/enable", + "events/task/task_newtask/enable" + ] + }, + { + "name" : "preemptoff", + "description" : "Preempt-disabled code section tracing", + "tag" : 0, + "type" : "KERNEL", + "sys-files" : [ + "events/preemptirq/preempt_enable/enable", + "events/preemptirq/preempt_disable/enable" + ] + }, + { + "name" : "binder", + "description" : "Binder kernel Info", + "tag" : 0, + "type" : "KERNEL", + "sys-files" : [ + "events/binder/binder_transaction/enable", + "events/binder/binder_transaction_received/enable", + "events/binder/binder_transaction_alloc_buf/enable", + "events/binder/binder_set_priority/enable", + "events/binder/binder_lock/enable", + "events/binder/binder_locked/enable", + "events/binder/binder_unlock/enable" + ] + }, + { + "name" : "sync", + "description" : "Synchronization", + "tag" : 0, + "type" : "KERNEL", + "sys-files" : [ + "events/dma_fence/enable" + ] + }, + { + "name" : "workq", + "description" : "Kernel Workqueues", + "tag" : 0, + "type" : "KERNEL", + "sys-files" : [ + "events/workqueue/enable" + ] + }, + { + "name" : "memreclaim", + "description" : "Kernel Memory Reclaim", + "tag" : 0, + "type" : "KERNEL", + "sys-files" : [ + "events/vmscan/mm_vmscan_direct_reclaim_begin/enable", + "events/vmscan/mm_vmscan_direct_reclaim_end/enable", + "events/vmscan/mm_vmscan_kswapd_wake/enable", + "events/vmscan/mm_vmscan_kswapd_sleep/enable", + "events/lowmemorykiller/enable" + ] + }, + { + "name" : "pagecache", + "description" : "Page cache", + "tag" : 0, + "type" : "KERNEL", + "sys-files" : [ + "events/filemap/enable" + ] + }, + { + "name" : "memory", + "description" : "memory", + "tag" : 0, + "type" : "KERNEL", + "sys-files" : [ + "events/kmem/rss_stat/enable", + "events/kmem/ion_heap_grow/enable", + "events/kmem/ion_heap_shrink/enable" + ] + } + ], + "USER" : [ + { + "name" : "ohos", + "description" : "OpenHarmony", + "tag" : 30, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "ability", + "description" : "Ability Manager", + "tag" : 31, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "zcamera", + "description" : "OpenHarmony Camera Module", + "tag" : 32, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "zmedia", + "description" : "OpenHarmony Media Module", + "tag" : 33, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "zimage", + "description" : "OpenHarmony Image Module", + "tag" : 34, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "zaudio", + "description" : "OpenHarmony Audio Module", + "tag" : 35, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "distributeddatamgr", + "description" : "Distributed Data Manager", + "tag" : 36, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "mdfs", + "description" : "Mobile Distributed File System", + "tag" : 37, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "graphic", + "description" : "Graphic Module", + "tag" : 38, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "ace", + "description" : "ACE development framework", + "tag" : 39, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "notification", + "description" : "Notification Module", + "tag" : 40, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "misc", + "description" : "misc Module", + "tag" : 41, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "multimodalinput", + "description" : "Multimodal Input Module", + "tag" : 42, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "sensors", + "description" : "Sensors Module", + "tag" : 43, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "msdp", + "description" : "Multimodal Sensor Data Platform", + "tag" : 44, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "dsoftbus", + "description" : "Distributed Softbus", + "tag" : 45, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "rpc", + "description" : "RPC and IPC", + "tag" : 46, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "ark", + "description" : "ARK Module", + "tag" : 47, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "window", + "description" : "Window Manager", + "tag" : 48, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "accessibility", + "description" : "Accessibility Manager", + "tag" : 61, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "account", + "description" : "Account Manager", + "tag" : 49, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "dhfwk", + "description" : "Distributed Hardware FWK", + "tag" : 52, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "dscreen", + "description" : "Distributed Screen", + "tag" : 50, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "daudio", + "description" : "Distributed Audio", + "tag" : 27, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "dinput", + "description" : "Distributed Input", + "tag" : 59, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "devicemanager", + "description" : "Device Manager", + "tag" : 54, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "samgr", + "description" : "samgr", + "tag" : 55, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "dsched", + "description" : "Distributed Schedule", + "tag" : 57, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "deviceprofile", + "description" : "Device Profile", + "tag" : 58, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "huks", + "description" : "Universal KeyStore", + "tag" : 25, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "dlpcre", + "description" : "Dlp Credential Service", + "tag" : 21, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "app", + "description" : "APP Module", + "tag" : 62, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "dcamera", + "description" : "Distributed Camera", + "tag" : 51, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "gresource", + "description" : "Global Resource Manager", + "tag" : 53, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "power", + "description" : "power Manager", + "tag" : 56, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "bluetooth", + "description" : "communicatio bluetooth", + "tag" : 60, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "filemanagement", + "description" : "filemanagement", + "tag" : 29, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "dslm", + "description" : "device security level", + "tag" : 28, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "useriam", + "description" : "useriam", + "tag" : 26, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "nweb", + "description" : "nweb", + "tag" : 24, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "net", + "description" : "net", + "tag" : 23, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "accesscontrol", + "description" : "Access Control Module", + "tag" : 22, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "interconn", + "description" : "Interconnection subsystem", + "tag" : 20, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "usb", + "description" : "usb subsystem", + "tag" : 19, + "type" : "USER", + "sys-files" : [ + ] + }, + { + "name" : "hdf", + "description" : "hdf subsystem", + "tag" : 18, + "type" : "USER", + "sys-files" : [ + ] + } + ] +} diff --git a/services/modules/trace/init_trace_static.c b/services/modules/trace/init_trace_static.c new file mode 100644 index 00000000..cd12920f --- /dev/null +++ b/services/modules/trace/init_trace_static.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 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 +#include "init_module_engine.h" +#include "plugin_adapter.h" + +static int InitTraceEarlyHook(const HOOK_INFO *info, void *cookie) +{ + if (GetBootEventEnable()) { + PLUGIN_LOGI("init trace enabled."); +#ifndef STARTUP_INIT_TEST + InitModuleMgrInstall("inittrace"); +#endif + return 0; + } + return 0; +} + +MODULE_CONSTRUCTOR(void) +{ + // Depends on parameter service + InitAddPostPersistParamLoadHook(0, InitTraceEarlyHook); +} diff --git a/services/param/manager/param_manager.c b/services/param/manager/param_manager.c index 4c634424..4c379957 100644 --- a/services/param/manager/param_manager.c +++ b/services/param/manager/param_manager.c @@ -336,7 +336,7 @@ INIT_LOCAL_API int GetServiceCtrlInfo(const char *name, const char *value, Servi const ParamCmdInfo *other = GetOtherSpecial(&size); for (size_t i = 0; i < size; i++) { if (strncmp(name, other[i].name, strlen(other[i].name)) == 0) { - return CreateCtrlInfo(ctrlInfo, other[i].cmd, strlen(other[i].name), 0, "%s.%s", name, value); + return CreateCtrlInfo(ctrlInfo, other[i].cmd, strlen(other[i].replace), 0, "%s.%s", name, value); } } return 0; diff --git a/test/unittest/BUILD.gn b/test/unittest/BUILD.gn index c6a878cc..ed6d76db 100644 --- a/test/unittest/BUILD.gn +++ b/test/unittest/BUILD.gn @@ -255,6 +255,7 @@ ohos_unittest("init_unittest") { "//utils/system/safwk/native/include", "//third_party/bounds_checking_function/include", "//third_party/cJSON", + "//third_party/zlib", "//base/security/access_token/interfaces/innerkits/token_setproc/include", "//base/security/access_token/interfaces/innerkits/nativetoken/include", "//base/startup/init/services/sandbox/include", @@ -271,6 +272,7 @@ ohos_unittest("init_unittest") { "//third_party/googletest:gmock", "//third_party/googletest:gtest", "//third_party/mbedtls:mbedtls_shared", + "//third_party/zlib:libz", ] defines = [ @@ -371,5 +373,11 @@ ohos_unittest("init_unittest") { defines += [ "PARAM_FEATURE_DEVICEINFO" ] } + + sources += [ + "//base/startup/init/services/modules/trace/init_trace.c", + "//base/startup/init/services/modules/trace/init_trace_static.c", + "//base/startup/init/test/unittest/modules/trace_unittest.cpp", + ] cflags_cc = [ "-fexceptions" ] } diff --git a/test/unittest/modules/trace_unittest.cpp b/test/unittest/modules/trace_unittest.cpp new file mode 100644 index 00000000..5c7eb4c2 --- /dev/null +++ b/test/unittest/modules/trace_unittest.cpp @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2023 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 "bootstage.h" +#include "init_utils.h" +#include "init_cmds.h" +#include "init_cmdexecutor.h" +#include "param_stub.h" +#include "securec.h" + +using namespace std; +using namespace testing::ext; + +namespace init_ut { +static const char *g_content = + "\"KERNEL\" : [" + "{" + "\"name\" : \"disk\"," + "\"description\" : \"Disk I/O\"," + "\"tag\" : 0," + "\"type\" : \"KERNEL\"," + "\"sys-files\" : [" + "\"events/f2fs/f2fs_sync_file_enter/enable\"," + "\"events/f2fs/f2fs_sync_file_exit/enable\"," + "\"events/f2fs/f2fs_write_begin/enable\"," + "\"events/f2fs/f2fs_write_end/enable\"," + "\"events/ext4/ext4_da_write_begin/enable\"," + "\"events/ext4/ext4_da_write_end/enable\"," + "\"events/ext4/ext4_sync_file_enter/enable\"," + "\"events/ext4/ext4_sync_file_exit/enable\"," + "\"events/block/block_rq_issue/enable\"," + "\"events/block/block_rq_complete/enable\"" + "]" + "}," + "{" + "\"name\" : \"mmc\"," + "\"description\" : \"eMMC commands\"," + "\"tag\" : 0," + "\"type\" : \"KERNEL\"," + "\"sys-files\" : [" + "\"events/mmc/enable\"" + "]" + "}" + "]," + "\"USER\" : [" + "{" + "\"name\" : \"ohos\"," + "\"description\" : \"OpenHarmony\"," + "\"tag\" : 30," + "\"type\" : \"USER\"," + "\"sys-files\" : [" + "]" + "}," + "{" + "\"name\" : \"ability\"," + "\"description\" : \"Ability Manager\"," + "\"tag\" : 31," + "\"type\" : \"USER\"," + "\"sys-files\" : [" + "]" + "}," + "{" + "\"name\" : \"usb\"," + "\"description\" : \"usb subsystem\"," + "\"tag\" : 19," + "\"type\" : \"USER\"," + "\"sys-files\" : [" + "]" + "}" + "]" +"}"; +void CreateInitTraceConfig(int compress) +{ + std::string config = "{ \"compress\" : "; + if (!compress) { + config += "false,"; + } else { + config += "true, "; + } + config += g_content; + // create trace cfg + CreateTestFile(STARTUP_INIT_UT_PATH"/system/etc/init_trace.cfg", config.c_str()); +} + +class TraceUnitTest : public testing::Test { +public: + static void SetUpTestCase(void) {}; + static void TearDownTestCase(void) {}; + void SetUp() {}; + void TearDown() {}; +}; + +HWTEST_F(TraceUnitTest, TraceTest_001, TestSize.Level1) +{ + // open switch for trace + uint32_t dataIndex = 0; + WriteParam("persist.init.bootevent.enable", "true", &dataIndex, 0); + HookMgrExecute(GetBootStageHookMgr(), INIT_POST_PERSIST_PARAM_LOAD, NULL, NULL); + // close switch for trace + WriteParam("persist.init.bootevent.enable", "false", &dataIndex, 0); + HookMgrExecute(GetBootStageHookMgr(), INIT_POST_PERSIST_PARAM_LOAD, NULL, NULL); +} + +HWTEST_F(TraceUnitTest, TraceTest_002, TestSize.Level1) +{ + CreateInitTraceConfig(1); + // start trace + PluginExecCmdByName("init_trace", "start"); + // for run 1 s + sleep(1); + // stop trace + PluginExecCmdByName("init_trace", "stop"); +} + +HWTEST_F(TraceUnitTest, TraceTest_003, TestSize.Level1) +{ + CreateInitTraceConfig(0); + // start trace + PluginExecCmdByName("init_trace", "start"); + // for run 1 s + sleep(1); + // stop trace + PluginExecCmdByName("init_trace", "stop"); +} + +HWTEST_F(TraceUnitTest, TraceTest_004, TestSize.Level1) +{ + std::string cmdArgs = "/system/etc/init_trace.cfg "; + cmdArgs += STARTUP_INIT_UT_PATH"/system/etc/init_trace.cfg"; + DoCmdByName("copy ", cmdArgs.c_str()); + // start trace + PluginExecCmdByName("init_trace", "start"); + // for run 1 s + sleep(1); + // stop trace + PluginExecCmdByName("init_trace", "stop"); +} + +HWTEST_F(TraceUnitTest, TraceTest_005, TestSize.Level1) +{ + // start trace + PluginExecCmdByName("init_trace", "start"); + // for run 1 s + sleep(1); + // interrupt trace + PluginExecCmdByName("init_trace", "1"); +} +} // namespace init_ut -- GitLab