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