1/* 2 * Copyright (c) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "sys_event.h" 17 18#include <inttypes.h> 19#include <time.h> 20#include <sys/time.h> 21 22#include "bootevent.h" 23#include "init_module_engine.h" 24#include "init_param.h" 25#include "plugin_adapter.h" 26#include "securec.h" 27#include "init_utils.h" 28 29typedef struct { 30 char *buffer; 31 uint32_t bufferLen; 32 uint32_t currLen; 33} EventArgs; 34 35static int GetServiceName(const char *paramName, char *buffer, size_t buffSize) 36{ 37 size_t len = strlen(paramName); 38 size_t i = 0; 39 for (size_t index = strlen("bootevent."); index < len; index++) { 40 PLUGIN_CHECK(i <= buffSize, return -1); 41 if (*(paramName + index) == '.') { 42 break; 43 } 44 buffer[i++] = *(paramName + index); 45 } 46 return (int)i; 47} 48 49static int TraversalEvent(ListNode *node, void *root) 50{ 51 BOOT_EVENT_PARAM_ITEM *item = (BOOT_EVENT_PARAM_ITEM *)node; 52 if (item->flags != BOOTEVENT_TYPE_SERVICE) { 53 return 0; 54 } 55 EventArgs *args = (EventArgs *)root; 56 int len = GetServiceName(item->paramName, args->buffer + args->currLen, args->bufferLen - args->currLen); 57 PLUGIN_CHECK(len > 0 && (((uint32_t)len + args->currLen) < args->bufferLen), return -1, 58 "Failed to format service name %s", item->paramName); 59 args->currLen += (uint32_t)len; 60 61 len = sprintf_s(args->buffer + args->currLen, args->bufferLen - args->currLen, ",%u:%u,%u:%u;", 62 (uint32_t)item->timestamp[BOOTEVENT_FORK].tv_sec, 63 (uint32_t)(item->timestamp[BOOTEVENT_FORK].tv_nsec / USTONSEC), 64 (uint32_t)item->timestamp[BOOTEVENT_READY].tv_sec, 65 (uint32_t)(item->timestamp[BOOTEVENT_READY].tv_nsec / USTONSEC)); 66 PLUGIN_CHECK(len > 0 && (((uint32_t)len + args->currLen) < args->bufferLen), return -1, 67 "Failed to format service time %s", item->paramName); 68 args->currLen += (uint32_t)len; 69 return 0; 70} 71 72static void InsertBootTimeParam(char *buffer, const char *name) 73{ 74 char bufKernel[MAX_BUFFER_LEN] = {0}; 75 char buf[MAX_BUFFER_LEN] = {0}; 76 char bootName[MAX_BUFFER_LEN] = {0}; 77 uint32_t bufLen = MAX_BUFFER_LEN; 78 uint32_t kernelLen = MAX_BUFFER_LEN; 79 int len = sprintf_s(bootName, MAX_BUFFER_LEN, "ohos.boot.time.%s", name); 80 PLUGIN_CHECK(len > 0 && ((uint32_t)len < MAX_BUFFER_LEN), return, "Failed to format boot name "); 81 int ret = SystemReadParam(bootName, buf, &bufLen); 82 PLUGIN_CHECK(ret == 0, return, "Failed to read boot time "); 83 char time[MAX_BUFFER_LEN] = {0}; 84 if (strcmp(name, "kernel") == 0) { 85 len = sprintf_s(time, MAX_BUFFER_LEN, ";kernel,0,%s", buf); 86 } else { 87 int result = SystemReadParam("ohos.boot.time.kernel", bufKernel, &kernelLen); 88 if (result == 0) { 89 len = sprintf_s(time, MAX_BUFFER_LEN, ";init,%s,%s", bufKernel, buf); 90 } 91 } 92 PLUGIN_CHECK(len > 0 && ((uint32_t)len < MAX_BUFFER_LEN), return, "Failed to format boot time "); 93 ret = strcat_s(buffer, MAX_BUFFER_FOR_EVENT + PARAM_VALUE_LEN_MAX + MAX_BUFFER_LEN + 1, time); 94 PLUGIN_CHECK(ret == 0, return, "Failed to format boot time "); 95} 96 97PLUGIN_STATIC void ReportBootEventComplete(ListNode *events) 98{ 99 PLUGIN_CHECK(events != NULL, return, "Invalid events"); 100 struct timespec curr = {0}; 101 int ret = clock_gettime(CLOCK_MONOTONIC, &curr); 102 PLUGIN_CHECK(ret == 0, return); 103 104 char *buffer = (char *)calloc(MAX_BUFFER_FOR_EVENT + PARAM_VALUE_LEN_MAX, 1); 105 PLUGIN_CHECK(buffer != NULL, return, "Failed to get memory for sys event "); 106 EventArgs args = { buffer, MAX_BUFFER_FOR_EVENT, 0 }; 107 OH_ListTraversal(events, (void *)&args, TraversalEvent, 0); 108 if ((args.currLen > 1) && (args.currLen < MAX_BUFFER_FOR_EVENT)) { 109 buffer[args.currLen - 1] = '\0'; 110 } 111 InsertBootTimeParam(buffer, "kernel"); 112 InsertBootTimeParam(buffer, "init"); 113 114 StartupTimeEvent startupTime = {}; 115 startupTime.event.type = STARTUP_TIME; 116 startupTime.totalTime = curr.tv_sec; 117 startupTime.totalTime = startupTime.totalTime * MSECTONSEC; 118 startupTime.totalTime += curr.tv_nsec / USTONSEC; 119 startupTime.detailTime = buffer; 120 char *reason = buffer + MAX_BUFFER_FOR_EVENT; 121 uint32_t size = PARAM_VALUE_LEN_MAX; 122 ret = SystemReadParam("ohos.boot.bootreason", reason, &size); 123 if (ret == 0) { 124 startupTime.reason = reason; 125 startupTime.firstStart = 1; 126 } else { 127 startupTime.reason = ""; 128 startupTime.firstStart = 0; 129 } 130 PLUGIN_LOGI("SysEventInit %u.%u detailTime len %u '%s'", 131 (uint32_t)curr.tv_sec, (uint32_t)(curr.tv_nsec / USTONSEC), args.currLen, startupTime.detailTime); 132 ReportSysEvent(&startupTime.event); 133 free(buffer); 134} 135 136#ifndef STARTUP_INIT_TEST // do not install 137MODULE_CONSTRUCTOR(void) 138{ 139 ReportBootEventComplete(GetBootEventList()); 140} 141#endif 142