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
29 typedef struct {
30 char *buffer;
31 uint32_t bufferLen;
32 uint32_t currLen;
33 } EventArgs;
34
GetServiceName(const char * paramName,char * buffer,size_t buffSize)35 static 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
TraversalEvent(ListNode * node,void * root)49 static 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
InsertBootTimeParam(char * buffer,const char * name)72 static 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
ReportBootEventComplete(ListNode * events)97 PLUGIN_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
MODULE_CONSTRUCTOR(void)137 MODULE_CONSTRUCTOR(void)
138 {
139 ReportBootEventComplete(GetBootEventList());
140 }
141 #endif
142