• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 <errno.h>
17 #include <inttypes.h>
18 #include <limits.h>
19 #include <signal.h>
20 
21 #include "securec.h"
22 #include "init.h"
23 #include "init_log.h"
24 #include "init_utils.h"
25 #include "init_service.h"
26 
GetCgroupPath(Service * service,char * buffer,uint32_t buffLen)27 INIT_STATIC int GetCgroupPath(Service *service, char *buffer, uint32_t buffLen)
28 {
29     int ret = snprintf_s(buffer, buffLen, buffLen - 1, "/dev/pids/native/%s/pid_%d/", service->name, service->pid);
30     INIT_ERROR_CHECK(ret > 0, return ret, "Failed to snprintf_s in GetCgroupPath, errno: %d", errno);
31     INIT_LOGV("Cgroup path %s ", buffer);
32     return 0;
33 }
34 
WriteToFile(const char * path,pid_t pid)35 static int WriteToFile(const char *path, pid_t pid)
36 {
37     INIT_CHECK_RETURN_VALUE(pid != 0, -1);
38     char pidName[PATH_MAX] = {0};
39     int fd = open(path, O_RDWR | O_APPEND);
40     INIT_ERROR_CHECK(fd >= 0, return -1, "Failed to open file errno: %d path: %s", errno, path);
41     int ret = 0;
42     INIT_LOGV(" WriteToFile pid %d", pid);
43     do {
44         ret = snprintf_s(pidName, sizeof(pidName), sizeof(pidName) - 1, "%d", pid);
45         INIT_ERROR_CHECK(ret > 0, break, "Failed to snprintf_s in WriteToFile, errno: %d", errno);
46         ret = write(fd, pidName, strlen(pidName));
47         INIT_ERROR_CHECK(ret > 0, break, "Failed to write file errno: %d path: %s %s", errno, path, pidName);
48         ret = 0;
49     } while (0);
50 
51     close(fd);
52     return ret;
53 }
54 
KillProcessesByCGroup(const char * path,Service * service)55 static void KillProcessesByCGroup(const char *path, Service *service)
56 {
57     FILE *file = fopen(path, "r");
58     INIT_ERROR_CHECK(file != NULL, return, "Open file fail %s errno: %d", path, errno);
59     pid_t pid = 0;
60     while (fscanf_s(file, "%d\n", &pid) == 1 && pid > 0) {
61         INIT_LOGV(" KillProcessesByCGroup pid %d ", pid);
62         if (pid == service->pid) {
63             continue;
64         }
65         INIT_LOGI("Kill service pid %d now ...", pid);
66         if (kill(pid, SIGKILL) != 0) {
67             INIT_LOGE("Unable to kill process, pid: %d ret: %d", pid, errno);
68         }
69     }
70     (void)fclose(file);
71 }
72 
DoRmdir(const TimerHandle handler,void * context)73 static void DoRmdir(const TimerHandle handler, void *context)
74 {
75     UNUSED(handler);
76     Service *service = (Service *)context;
77     INIT_ERROR_CHECK(service != NULL, return, "Service timer process with invalid service");
78     ServiceStopTimer(service);
79 
80     char path[PATH_MAX] = {};
81     int ret = GetCgroupPath(service, path, sizeof(path));
82     free(service->name);
83     free(service);
84     INIT_ERROR_CHECK(ret == 0, return, "Failed to get real path errno: %d", errno);
85     ret = rmdir(path);
86     if (ret != 0) {
87         INIT_LOGE("Failed to rmdir %s errno: %d", path, errno);
88     }
89 }
90 
RmdirTimer(Service * service,uint64_t timeout)91 static void RmdirTimer(Service *service, uint64_t timeout)
92 {
93     Service *serviceRmdir = (Service *)calloc(1, sizeof(Service));
94     INIT_ERROR_CHECK(serviceRmdir != NULL, return, "Failed to malloc for serviceRmdir");
95     serviceRmdir->pid = service->pid;
96     int strLen = strlen(service->name);
97     serviceRmdir->name = (char *)malloc(sizeof(char)*(strLen + 1));
98     INIT_ERROR_CHECK(serviceRmdir->name != NULL, free(serviceRmdir); return, "Failed to malloc for serviceRmdir->name");
99     int ret = strcpy_s(serviceRmdir->name, strLen + 1, service->name);
100     if (ret != 0) {
101         free(serviceRmdir->name);
102         free(serviceRmdir);
103         INIT_LOGE("Failed to copy, ret: %d", errno);
104         return;
105     }
106     LE_STATUS status = LE_CreateTimer(LE_GetDefaultLoop(), &serviceRmdir->timer, DoRmdir, (void *)serviceRmdir);
107     if (status != LE_SUCCESS) {
108         INIT_LOGE("Create service timer for service \' %s Rmdir \' failed, status = %d", serviceRmdir->name, status);
109         free(serviceRmdir->name);
110         free(serviceRmdir);
111         return;
112     }
113     status = LE_StartTimer(LE_GetDefaultLoop(), serviceRmdir->timer, timeout, 1);
114     if (status != LE_SUCCESS) {
115         INIT_LOGE("Start service timer for service \' %s Rmdir \' failed, status = %d", serviceRmdir->name, status);
116         free(serviceRmdir->name);
117         free(serviceRmdir);
118     }
119 }
120 
ProcessServiceDied(Service * service)121 int ProcessServiceDied(Service *service)
122 {
123     INIT_CHECK_RETURN_VALUE(service != NULL, -1);
124     INIT_CHECK_RETURN_VALUE(service->pid != -1, 0);
125     INIT_CHECK_RETURN_VALUE(service->isCgroupEnabled, 0);
126     char path[PATH_MAX] = {};
127     INIT_LOGV("ProcessServiceDied %d to cgroup ", service->pid);
128     int ret = GetCgroupPath(service, path, sizeof(path));
129     INIT_ERROR_CHECK(ret == 0, return -1, "Failed to get real path errno: %d", errno);
130     ret = strcat_s(path, sizeof(path), "cgroup.procs");
131     INIT_ERROR_CHECK(ret == 0, return ret, "Failed to strcat_s errno: %d", errno);
132     KillProcessesByCGroup(path, service);
133     RmdirTimer(service, 200);  // 200ms
134     return ret;
135 }
136 
ProcessServiceAdd(Service * service)137 int ProcessServiceAdd(Service *service)
138 {
139     INIT_CHECK_RETURN_VALUE(service != NULL, -1);
140     INIT_CHECK_RETURN_VALUE(service->isCgroupEnabled, 0);
141     char path[PATH_MAX] = {};
142     INIT_LOGV("ProcessServiceAdd %d to cgroup ", service->pid);
143     int ret = GetCgroupPath(service, path, sizeof(path));
144     INIT_ERROR_CHECK(ret == 0, return -1, "Failed to get real path errno: %d", errno);
145     (void)MakeDirRecursive(path, 0755);  // 0755 default mode
146     ret = strcat_s(path, sizeof(path), "cgroup.procs");
147     INIT_ERROR_CHECK(ret == 0, return ret, "Failed to strcat_s errno: %d", errno);
148     ret = WriteToFile(path, service->pid);
149     INIT_ERROR_CHECK(ret == 0, return ret, "write pid to cgroup.procs fail %s", path);
150     INIT_LOGV("Add service %d to cgroup %s success", service->pid, path);
151     return 0;
152 }