bootevent.c 12.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
 * Copyright (c) 2021 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 <stdbool.h>
#include "init_module_engine.h"
#include "trigger_manager.h"
#include "init_log.h"
M
Mupceet 已提交
20
#include "plugin_adapter.h"
M
Mupceet 已提交
21 22 23 24
#include "init_hook.h"
#include "init_service.h"
#include "bootstage.h"
#include "securec.h"
25
#include "init_utils.h"
26 27 28

#define BOOT_EVENT_PARA_PREFIX      "bootevent."
#define BOOT_EVENT_PARA_PREFIX_LEN  10
M
Mupceet 已提交
29
#define BOOT_EVENT_TIMESTAMP_MAX_LEN  50
30 31 32 33 34
#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/"
C
codex  
chengjinsong 已提交
35
static int g_bootEventNum = 0;
M
Mupceet 已提交
36 37 38 39 40 41 42

enum {
    BOOTEVENT_FORK,
    BOOTEVENT_READY,
    BOOTEVENT_MAX
};

43 44
typedef struct tagBOOT_EVENT_PARAM_ITEM {
    ListNode    node;
45
    char  *paramName;
M
Mupceet 已提交
46
    struct timespec timestamp[BOOTEVENT_MAX];
47 48
} BOOT_EVENT_PARAM_ITEM;

M
Mupceet 已提交
49
static ListNode bootEventList = {&bootEventList, &bootEventList};
50

M
Mupceet 已提交
51
static int BootEventParaListCompareProc(ListNode *node, void *data)
52
{
M
Mupceet 已提交
53 54 55
    BOOT_EVENT_PARAM_ITEM *item = (BOOT_EVENT_PARAM_ITEM *)node;
    if (strcmp(item->paramName + BOOT_EVENT_PARA_PREFIX_LEN, (const char *)data) == 0) {
        return 0;
56
    }
M
Mupceet 已提交
57
    return -1;
58 59
}

60 61 62 63 64 65 66 67 68
static int ParseBooteventCompareProc(ListNode *node, void *data)
{
    BOOT_EVENT_PARAM_ITEM *item = (BOOT_EVENT_PARAM_ITEM *)node;
    if (strcmp(item->paramName, (const char *)data) == 0) {
        return 0;
    }
    return -1;
}

M
Mupceet 已提交
69
static int AddServiceBootEvent(const char *serviceName, const char *paramName)
70
{
M
Mupceet 已提交
71 72
    ServiceExtData *extData = NULL;
    ListNode *found = NULL;
73
    if (strncmp(paramName, BOOT_EVENT_PARA_PREFIX, BOOT_EVENT_PARA_PREFIX_LEN) != 0) {
M
Mupceet 已提交
74
        return -1;
75
    }
76
    found = OH_ListFind(&bootEventList, (void *)paramName, ParseBooteventCompareProc);
M
Mupceet 已提交
77 78
    if (found != NULL) {
        return -1;
79
    }
M
Mupceet 已提交
80 81 82 83 84
    for (int i = HOOK_ID_BOOTEVENT; i < HOOK_ID_BOOTEVENT_MAX; i++) {
        extData = AddServiceExtData(serviceName, i, NULL, sizeof(BOOT_EVENT_PARAM_ITEM));
        if (extData != NULL) {
            break;
        }
85
    }
M
Mupceet 已提交
86 87
    if (extData == NULL) {
        return -1;
88
    }
M
Mupceet 已提交
89 90 91 92 93
    BOOT_EVENT_PARAM_ITEM *item = (BOOT_EVENT_PARAM_ITEM *)extData->data;
    OH_ListInit(&item->node);
    for (int i = 0; i < BOOTEVENT_MAX; i++) {
        item->timestamp[i].tv_nsec = 0;
        item->timestamp[i].tv_sec = 0;
94
    }
M
Mupceet 已提交
95 96
    item->paramName = strdup(paramName);
    if (item->paramName == NULL) {
97
        DelServiceExtData(serviceName, extData->dataId);
M
Mupceet 已提交
98 99
        INIT_LOGI("strdup failed");
        return -1;
100
    }
M
Mupceet 已提交
101 102
    OH_ListAddTail(&bootEventList, (ListNode *)&item->node);
    return 0;
103 104
}

C
cheng_jinsong 已提交
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
static void AddInitBootEvent(const char *bootEventName)
{
    ListNode *found = NULL;
    found = OH_ListFind(&bootEventList, (void *)bootEventName, ParseBooteventCompareProc);
    if (found != NULL) {
        INIT_CHECK_ONLY_RETURN(clock_gettime(CLOCK_MONOTONIC,
            &(((BOOT_EVENT_PARAM_ITEM *)found)->timestamp[BOOTEVENT_READY])) == 0);
        return;
    }

    BOOT_EVENT_PARAM_ITEM *item = malloc(sizeof(BOOT_EVENT_PARAM_ITEM));
    if (item == NULL) {
        return;
    }
    OH_ListInit(&item->node);
    if (clock_gettime(CLOCK_MONOTONIC, &(item->timestamp[BOOTEVENT_FORK])) != 0) {
        free(item);
        return;
    }
    item->paramName = strdup(bootEventName);
    if (item->paramName == NULL) {
        free(item);
        return;
    }
    OH_ListAddTail(&bootEventList, (ListNode *)&item->node);
    return;
}

133 134 135 136
#define BOOT_EVENT_BOOT_COMPLETED "bootevent.boot.completed"

static void BootEventParaFireByName(const char *paramName)
{
M
Mupceet 已提交
137 138 139
    ListNode *found = NULL;
    char *bootEventValue = strrchr(paramName, '.');
    if (bootEventValue == NULL) {
140 141
        return;
    }
M
Mupceet 已提交
142
    bootEventValue[0] = '\0';
143

M
Mupceet 已提交
144 145 146
    found = OH_ListFind(&bootEventList, (void *)paramName, BootEventParaListCompareProc);
    if (found == NULL) {
        return;
147
    }
M
Mupceet 已提交
148 149 150 151 152
    if (((BOOT_EVENT_PARAM_ITEM *)found)->timestamp[BOOTEVENT_READY].tv_sec != 0) {
        return;
    }
    INIT_CHECK_ONLY_RETURN(clock_gettime(CLOCK_MONOTONIC,
        &(((BOOT_EVENT_PARAM_ITEM *)found)->timestamp[BOOTEVENT_READY])) == 0);
C
codex  
chengjinsong 已提交
153
    g_bootEventNum--;
154
    // Check if all boot event params are fired
C
codex  
chengjinsong 已提交
155
    if (g_bootEventNum > 0) {
156 157 158
        return;
    }
    // All parameters are fired, set boot completed now ...
C
cheng_jinsong 已提交
159
    INIT_LOGI("All boot events are fired, boot complete now ...");
160
    SystemWriteParam(BOOT_EVENT_BOOT_COMPLETED, "true");
M
Mupceet 已提交
161
    return;
162 163 164 165 166
}

#define BOOT_EVENT_FIELD_NAME "bootevents"
static void ServiceParseBootEventHook(SERVICE_PARSE_CTX *serviceParseCtx)
{
M
Mupceet 已提交
167 168 169
    int cnt;
    cJSON *bootEvents = cJSON_GetObjectItem(serviceParseCtx->serviceNode, BOOT_EVENT_FIELD_NAME);

C
cheng_jinsong 已提交
170
    // No boot events in config file
M
Mupceet 已提交
171 172 173
    if (bootEvents == NULL) {
        return;
    }
174 175 176
    SERVICE_INFO_CTX ctx = {0};
    ctx.serviceName = serviceParseCtx->serviceName;
    HookMgrExecute(GetBootStageHookMgr(), INIT_SERVICE_CLEAR, (void *)&ctx, NULL);
C
cheng_jinsong 已提交
177
    // Single boot event in config file
M
Mupceet 已提交
178 179 180
    if (!cJSON_IsArray(bootEvents)) {
        if (AddServiceBootEvent(serviceParseCtx->serviceName,
            cJSON_GetStringValue(bootEvents)) != 0) {
C
cheng_jinsong 已提交
181
            INIT_LOGI("Add service bootEvent failed %s", serviceParseCtx->serviceName);
M
Mupceet 已提交
182 183
            return;
        }
C
codex  
chengjinsong 已提交
184
        g_bootEventNum++;
M
Mupceet 已提交
185 186 187
        return;
    }

C
cheng_jinsong 已提交
188
    // Multiple boot events in config file
M
Mupceet 已提交
189 190 191 192 193
    cnt = cJSON_GetArraySize(bootEvents);
    for (int i = 0; i < cnt; i++) {
        cJSON *item = cJSON_GetArrayItem(bootEvents, i);
        if (AddServiceBootEvent(serviceParseCtx->serviceName,
            cJSON_GetStringValue(item)) != 0) {
C
cheng_jinsong 已提交
194
            INIT_LOGI("Add service bootEvent failed %s", serviceParseCtx->serviceName);
195
            continue;
M
Mupceet 已提交
196
        }
C
codex  
chengjinsong 已提交
197
        g_bootEventNum++;
M
Mupceet 已提交
198
    }
M
Mupceet 已提交
199
}
200

M
Mupceet 已提交
201 202 203
static int DoBootEventCmd(int id, const char *name, int argc, const char **argv)
{
    PLUGIN_CHECK(argc >= 1, return -1, "Invalid parameter");
C
cheng_jinsong 已提交
204 205 206 207 208 209
    if (strcmp(argv[0], "init") == 0) {
        AddInitBootEvent(argv[1]);
    } else {
        // argv[0] samgr.ready.true
        BootEventParaFireByName(argv[0]);
    }
M
Mupceet 已提交
210 211
    return 0;
}
212

C
cheng_jinsong 已提交
213
static int AddItemToJson(cJSON *root, const char *name, double startTime, int tid, double durTime)
214 215 216 217
{
    cJSON *obj = cJSON_CreateObject(); // release obj at traverse done
    INIT_CHECK_RETURN_VALUE(obj != NULL, -1);
    cJSON_AddStringToObject(obj, "name", name);
C
cheng_jinsong 已提交
218
    cJSON_AddNumberToObject(obj, "ts", startTime);
219 220 221 222 223 224 225 226
    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;
}

C
cheng_jinsong 已提交
227
static int BootEventTraversal(ListNode *node, void *root)
228
{
C
cheng_jinsong 已提交
229
    static int tid = 1; // 1 boot event start num
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
    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);
C
cheng_jinsong 已提交
252 253
    char bootEventFileName[BOOT_EVENT_FILEPATH_MAX_LEN] = "";
    INIT_CHECK_RETURN_VALUE(snprintf(bootEventFileName, BOOT_EVENT_FILEPATH_MAX_LEN,
254 255
        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
C
cheng_jinsong 已提交
256 257
    CheckAndCreatFile(bootEventFileName, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
    FILE *tmpFile = fopen(bootEventFileName, "wr");
258 259
    INIT_CHECK_RETURN_VALUE(tmpFile != NULL, -1);
    cJSON *root = cJSON_CreateArray();
C
cheng_jinsong 已提交
260 261 262 263 264
    if (root == NULL) {
        (void)fclose(tmpFile);
        return -1;
    }
    OH_ListTraversal(&bootEventList, (void *)root, BootEventTraversal, 0);
265
    char *buff = cJSON_Print(root);
C
cheng_jinsong 已提交
266 267 268 269 270 271
    if (buff == NULL) {
        cJSON_Delete(root);
        (void)fclose(tmpFile);
        return -1;
    }
    INIT_CHECK_ONLY_ELOG(fprintf(tmpFile, "%s\n", buff) >= 0, "save boot event file failed");
272 273 274 275 276 277 278
    free(buff);
    cJSON_Delete(root);
    (void)fflush(tmpFile);
    (void)fclose(tmpFile);
    return 0;
}

M
Mupceet 已提交
279 280
static int32_t g_executorId = -1;
static int ParamSetBootEventHook(const HOOK_INFO *hookInfo, void *cookie)
281
{
M
Mupceet 已提交
282 283
    if (g_executorId == -1) {
        g_executorId = AddCmdExecutor("bootevent", DoBootEventCmd);
284
        AddCmdExecutor("save.bootevent", SaveServiceBootEvent);
285
    }
M
Mupceet 已提交
286
    return 0;
287 288
}

M
Mupceet 已提交
289 290 291 292 293 294 295 296 297 298 299
static void DumpServiceBootEvent(SERVICE_INFO_CTX *serviceCtx)
{
    if (serviceCtx->reserved != NULL && strcmp(serviceCtx->reserved, "bootevent") != 0) {
        return;
    }
    for (int i = HOOK_ID_BOOTEVENT; i < HOOK_ID_BOOTEVENT_MAX; i++) {
        ServiceExtData *serviceExtData = GetServiceExtData(serviceCtx->serviceName, i);
        if (serviceExtData == NULL) {
            return;
        }
        BOOT_EVENT_PARAM_ITEM *item = (BOOT_EVENT_PARAM_ITEM *)serviceExtData->data;
C
cheng_jinsong 已提交
300 301 302
        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, "%f",
303 304
            item->timestamp[BOOTEVENT_FORK].tv_sec +
            (double)item->timestamp[BOOTEVENT_FORK].tv_nsec / SECTONSEC) >= 0);
C
cheng_jinsong 已提交
305
        INIT_CHECK_ONLY_RETURN(sprintf_s(bootEventReadyTimeStamp, BOOT_EVENT_TIMESTAMP_MAX_LEN, "%f",
306 307
            (long)item->timestamp[BOOTEVENT_READY].tv_sec +
            (double)item->timestamp[BOOTEVENT_READY].tv_nsec / SECTONSEC) >= 0);
M
Mupceet 已提交
308
        printf("\t%-20.20s\t%-50s\t%-20.20s\t%-20.20s\n", serviceCtx->serviceName, item->paramName,
C
cheng_jinsong 已提交
309
            bootEventForkTimeStamp, bootEventReadyTimeStamp);
M
Mupceet 已提交
310 311 312 313 314 315 316 317 318 319 320 321
    }
    return;
}

static void ClearServiceBootEvent(SERVICE_INFO_CTX *serviceCtx)
{
    if (serviceCtx->reserved == NULL || strcmp(serviceCtx->reserved, "bootevent") == 0) {
        for (int i = HOOK_ID_BOOTEVENT; i < HOOK_ID_BOOTEVENT_MAX; i++) {
            ServiceExtData *extData = GetServiceExtData(serviceCtx->serviceName, i);
            if (extData == NULL) {
                return;
            }
322
            free(((BOOT_EVENT_PARAM_ITEM *)extData->data)->paramName);
M
Mupceet 已提交
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
            OH_ListRemove(&((BOOT_EVENT_PARAM_ITEM *)extData->data)->node);
            DelServiceExtData(serviceCtx->serviceName, i);
        }
    }
    return;
}

static void SetServiceBootEventFork(SERVICE_INFO_CTX *serviceCtx)
{
    for (int i = HOOK_ID_BOOTEVENT; i < HOOK_ID_BOOTEVENT_MAX; i++) {
        ServiceExtData *extData = GetServiceExtData(serviceCtx->serviceName, i);
        if (extData == NULL || ((BOOT_EVENT_PARAM_ITEM *)extData->data)->timestamp[BOOTEVENT_FORK].tv_sec != 0) {
            return;
        }
        INIT_CHECK_ONLY_RETURN(clock_gettime(CLOCK_MONOTONIC,
            &(((BOOT_EVENT_PARAM_ITEM *)extData->data)->timestamp[BOOTEVENT_FORK])) == 0);
    }
    return;
}

343 344
MODULE_CONSTRUCTOR(void)
{
M
Mupceet 已提交
345 346 347
    InitAddServiceHook(SetServiceBootEventFork, INIT_SERVICE_FORK_BEFORE);
    InitAddServiceHook(ClearServiceBootEvent, INIT_SERVICE_CLEAR);
    InitAddServiceHook(DumpServiceBootEvent, INIT_SERVICE_DUMP);
348
    InitAddServiceParseHook(ServiceParseBootEventHook);
M
Mupceet 已提交
349
    InitAddGlobalInitHook(0, ParamSetBootEventHook);
350
}