• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 <dlfcn.h>
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <signal.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #ifdef __MUSL__
23 #include <stropts.h>
24 #endif
25 #include <sys/capability.h>
26 #include <sys/ioctl.h>
27 #include <sys/param.h>
28 #include <sys/resource.h>
29 #include <sys/stat.h>
30 #include <time.h>
31 #include <unistd.h>
32 
33 #include "init.h"
34 #include "init_adapter.h"
35 #include "init_cmds.h"
36 #include "init_cmdexecutor.h"
37 #include "init_log.h"
38 #include "init_cmdexecutor.h"
39 #include "init_jobs_internal.h"
40 #include "init_param.h"
41 #include "init_service.h"
42 #include "init_service_manager.h"
43 #include "init_service_socket.h"
44 #include "init_utils.h"
45 #include "fd_holder_internal.h"
46 #include "loop_event.h"
47 #include "securec.h"
48 #include "service_control.h"
49 
50 #ifndef OHOS_LITE
51 #include "hookmgr.h"
52 #include "bootstage.h"
53 #endif
54 
55 #ifdef WITH_SECCOMP
56 #define APPSPAWN_NAME ("appspawn")
57 #define NWEBSPAWN_NAME ("nwebspawn")
58 #endif
59 
60 #ifndef TIOCSCTTY
61 #define TIOCSCTTY 0x540E
62 #endif
63 
SetAllAmbientCapability(void)64 static int SetAllAmbientCapability(void)
65 {
66     for (int i = 0; i <= CAP_LAST_CAP; ++i) {
67         if (SetAmbientCapability(i) != 0) {
68             return SERVICE_FAILURE;
69         }
70     }
71     return SERVICE_SUCCESS;
72 }
73 
SetSystemSeccompPolicy(const Service * service)74 static int SetSystemSeccompPolicy(const Service *service)
75 {
76 #ifdef WITH_SECCOMP
77     if (strncmp(APPSPAWN_NAME, service->name, strlen(APPSPAWN_NAME))
78         && strncmp(NWEBSPAWN_NAME, service->name, strlen(NWEBSPAWN_NAME))) {
79         char cmdContent[MAX_CMD_CONTENT_LEN + 1] = {0};
80 
81         int rc = snprintf_s(cmdContent, MAX_CMD_CONTENT_LEN + 1, strlen(service->name) + 1,
82                             "%s ", service->name);
83         if (rc == -1) {
84             return SERVICE_FAILURE;
85         }
86 
87         rc = strcat_s(cmdContent, MAX_CMD_CONTENT_LEN + 1, service->pathArgs.argv[0]);
88         if (rc != 0) {
89             return SERVICE_FAILURE;
90         }
91 
92         PluginExecCmdByName("SetSeccompPolicy", cmdContent);
93     }
94 #endif
95     return SERVICE_SUCCESS;
96 }
97 
98 #ifndef OHOS_LITE
99 /**
100  * service Hooking
101  */
ServiceHookWrapper(const HOOK_INFO * hookInfo,void * executionContext)102 static int ServiceHookWrapper(const HOOK_INFO *hookInfo, void *executionContext)
103 {
104     SERVICE_INFO_CTX *serviceContext = (SERVICE_INFO_CTX *)executionContext;
105     ServiceHook realHook = (ServiceHook)hookInfo->hookCookie;
106 
107     realHook(serviceContext);
108     return 0;
109 };
110 
InitAddServiceHook(ServiceHook hook,int hookState)111 int InitAddServiceHook(ServiceHook hook, int hookState)
112 {
113     HOOK_INFO info;
114 
115     info.stage = hookState;
116     info.prio = 0;
117     info.hook = ServiceHookWrapper;
118     info.hookCookie = (void *)hook;
119 
120     return HookMgrAddEx(GetBootStageHookMgr(), &info);
121 }
122 
123 /**
124  * service hooking execute
125  */
ServiceHookExecute(const char * serviceName,const char * info,int stage)126 static void ServiceHookExecute(const char *serviceName, const char *info, int stage)
127 {
128     SERVICE_INFO_CTX context;
129 
130     context.serviceName = serviceName;
131     context.reserved = info;
132 
133     (void)HookMgrExecute(GetBootStageHookMgr(), stage, (void *)(&context), NULL);
134 }
135 #endif
136 
ServiceCheck(const Service * service)137 static int ServiceCheck(const Service *service)
138 {
139     if (service->servPerm.gIDCnt == 0) {
140         // use uid as gid
141         INIT_ERROR_CHECK(setgid(service->servPerm.uID) == 0, return SERVICE_FAILURE,
142             "SetPerms, setgid for %s failed. %d", service->name, errno);
143     }
144     if (service->servPerm.gIDCnt > 0) {
145         INIT_ERROR_CHECK(setgid(service->servPerm.gIDArray[0]) == 0, return SERVICE_FAILURE,
146             "SetPerms, setgid for %s failed. %d", service->name, errno);
147     }
148     if (service->servPerm.gIDCnt > 1) {
149         INIT_ERROR_CHECK(setgroups(service->servPerm.gIDCnt - 1, (const gid_t *)&service->servPerm.gIDArray[1]) == 0,
150             return SERVICE_FAILURE,
151             "SetPerms, setgroups failed. errno = %d, gIDCnt=%d", errno, service->servPerm.gIDCnt);
152     }
153 
154     return SERVICE_SUCCESS;
155 }
156 
SetPerms(const Service * service)157 static int SetPerms(const Service *service)
158 {
159     INIT_CHECK_RETURN_VALUE(KeepCapability() == 0, SERVICE_FAILURE);
160 
161     INIT_ERROR_CHECK(ServiceCheck(service) == SERVICE_SUCCESS, return SERVICE_FAILURE,
162         "set seccomp policy failed for service %s", service->name);
163 
164     // set seccomp policy before setuid
165     INIT_ERROR_CHECK(SetSystemSeccompPolicy(service) == SERVICE_SUCCESS, return SERVICE_FAILURE,
166         "set seccomp policy failed for service %s", service->name);
167 
168     if (service->servPerm.uID != 0) {
169         if (setuid(service->servPerm.uID) != 0) {
170             INIT_LOGE("setuid of service: %s failed, uid = %d", service->name, service->servPerm.uID);
171             return SERVICE_FAILURE;
172         }
173     }
174 
175     struct __user_cap_header_struct capHeader;
176     capHeader.version = _LINUX_CAPABILITY_VERSION_3;
177     capHeader.pid = 0;
178     struct __user_cap_data_struct capData[CAP_NUM] = {};
179     for (unsigned int i = 0; i < service->servPerm.capsCnt; ++i) {
180         if (service->servPerm.caps[i] == FULL_CAP) {
181             for (int j = 0; j < CAP_NUM; ++j) {
182                 capData[j].effective = FULL_CAP;
183                 capData[j].permitted = FULL_CAP;
184                 capData[j].inheritable = FULL_CAP;
185             }
186             break;
187         }
188         capData[CAP_TO_INDEX(service->servPerm.caps[i])].effective |= CAP_TO_MASK(service->servPerm.caps[i]);
189         capData[CAP_TO_INDEX(service->servPerm.caps[i])].permitted |= CAP_TO_MASK(service->servPerm.caps[i]);
190         capData[CAP_TO_INDEX(service->servPerm.caps[i])].inheritable |= CAP_TO_MASK(service->servPerm.caps[i]);
191     }
192 
193     INIT_ERROR_CHECK(capset(&capHeader, capData) == 0, return SERVICE_FAILURE,
194         "capset failed for service: %s, error: %d", service->name, errno);
195     for (unsigned int i = 0; i < service->servPerm.capsCnt; ++i) {
196         if (service->servPerm.caps[i] == FULL_CAP) {
197             return SetAllAmbientCapability();
198         }
199         INIT_ERROR_CHECK(SetAmbientCapability(service->servPerm.caps[i]) == 0, return SERVICE_FAILURE,
200             "SetAmbientCapability failed for service: %s", service->name);
201     }
202 #ifndef OHOS_LITE
203     /*
204      * service set Perms hooks
205      */
206     ServiceHookExecute(service->name, NULL, INIT_SERVICE_SET_PERMS);
207 #endif
208     return SERVICE_SUCCESS;
209 }
210 
WritePid(const Service * service)211 static int WritePid(const Service *service)
212 {
213     pid_t childPid = getpid();
214     for (int i = 0; i < service->writePidArgs.count; i++) {
215         if (service->writePidArgs.argv[i] == NULL) {
216             continue;
217         }
218         FILE *fd = NULL;
219         char *realPath = GetRealPath(service->writePidArgs.argv[i]);
220         if (realPath != NULL) {
221             fd = fopen(realPath, "wb");
222         } else {
223             fd = fopen(service->writePidArgs.argv[i], "wb");
224         }
225         if (fd != NULL) {
226             INIT_CHECK_ONLY_ELOG((int)fprintf(fd, "%d", childPid) > 0,
227                 "Failed to write %s pid:%d", service->writePidArgs.argv[i], childPid);
228             (void)fclose(fd);
229         } else {
230             INIT_LOGE("Failed to open realPath: %s  %s errno:%d.", realPath, service->writePidArgs.argv[i], errno);
231         }
232         if (realPath != NULL) {
233             free(realPath);
234         }
235         INIT_LOGV("ServiceStart writepid filename=%s, childPid=%d, ok", service->writePidArgs.argv[i], childPid);
236     }
237     return SERVICE_SUCCESS;
238 }
239 
CloseServiceFds(Service * service,bool needFree)240 void CloseServiceFds(Service *service, bool needFree)
241 {
242     INIT_ERROR_CHECK(service != NULL, return, "Service null");
243     INIT_LOGI("Closing service \' %s \' fds", service->name);
244     // fdCount > 0, There is no reason fds is NULL
245     if (service->fdCount != 0) {
246         size_t fdCount = service->fdCount;
247         int *fds = service->fds;
248         for (size_t i = 0; i < fdCount; i++) {
249             INIT_LOGV("Closing fd: %d", fds[i]);
250             if (fds[i] != -1) {
251                 close(fds[i]);
252                 fds[i] = -1;
253             }
254         }
255     }
256     service->fdCount = 0;
257     if (needFree && service->fds != NULL) {
258         free(service->fds);
259         service->fds = NULL;
260     }
261 }
262 
PublishHoldFds(Service * service)263 static void PublishHoldFds(Service *service)
264 {
265     INIT_ERROR_CHECK(service != NULL, return, "Publish hold fds with invalid service");
266     char fdBuffer[MAX_FD_HOLDER_BUFFER] = {};
267     if (service->fdCount > 0 && service->fds != NULL) {
268         size_t pos = 0;
269         for (size_t i = 0; i < service->fdCount; i++) {
270             int fd = dup(service->fds[i]);
271             if (fd < 0) {
272                 INIT_LOGE("Duplicate file descriptors of Service \' %s \' failed. err = %d", service->name, errno);
273                 continue;
274             }
275             INIT_ERROR_CHECK(!(snprintf_s((char *)fdBuffer + pos, sizeof(fdBuffer) - pos, sizeof(fdBuffer) - 1,
276                 "%d ", fd) < 0), return, "snprintf_s failed err=%d", errno);
277             pos = strlen(fdBuffer);
278         }
279         fdBuffer[pos - 1] = '\0'; // Remove last ' '
280         INIT_LOGI("fd buffer: [%s]", fdBuffer);
281         char envName[MAX_BUFFER_LEN] = {};
282         INIT_ERROR_CHECK(!(snprintf_s(envName, MAX_BUFFER_LEN, MAX_BUFFER_LEN - 1, ENV_FD_HOLD_PREFIX"%s",
283             service->name) < 0), return, "snprintf_s failed err=%d", errno);
284         INIT_CHECK_ONLY_ELOG(!(setenv(envName, fdBuffer, 1) < 0), "Failed to set env %s", envName);
285         INIT_LOGI("File descriptors of Service \' %s \' published", service->name);
286     }
287 }
288 
BindCpuCore(Service * service)289 static int BindCpuCore(Service *service)
290 {
291     if (service == NULL || service->cpuSet == NULL) {
292         return SERVICE_SUCCESS;
293     }
294     if (CPU_COUNT(service->cpuSet) == 0) {
295         return SERVICE_SUCCESS;
296     }
297 #ifndef __LITEOS_A__
298     int pid = getpid();
299     INIT_ERROR_CHECK(sched_setaffinity(pid, sizeof(cpu_set_t), service->cpuSet) == 0,
300         return SERVICE_FAILURE, "%s set affinity between process(pid=%d) with CPU's core failed", service->name, pid);
301     INIT_LOGI("%s set affinity between process(pid=%d) with CPU's core successfully", service->name, pid);
302 #endif
303     return SERVICE_SUCCESS;
304 }
305 
ClearEnvironment(Service * service)306 static void ClearEnvironment(Service *service)
307 {
308     if (strcmp(service->name, "appspawn") != 0 && strcmp(service->name, "nwebspawn") != 0) {
309         sigset_t mask;
310         sigemptyset(&mask);
311         sigaddset(&mask, SIGCHLD);
312         sigaddset(&mask, SIGTERM);
313         sigprocmask(SIG_UNBLOCK, &mask, NULL);
314     }
315     return;
316 }
317 
InitServiceProperties(Service * service)318 static int InitServiceProperties(Service *service)
319 {
320     INIT_ERROR_CHECK(service != NULL, return -1, "Invalid parameter.");
321     SetServiceEnterSandbox(service->pathArgs.argv[0], service->attribute);
322     INIT_CHECK_ONLY_ELOG(SetAccessToken(service) == SERVICE_SUCCESS,
323         "Set service %s access token failed", service->name);
324     // deal start job
325     if (service->serviceJobs.jobsName[JOB_ON_START] != NULL) {
326         DoJobNow(service->serviceJobs.jobsName[JOB_ON_START]);
327     }
328     ClearEnvironment(service);
329     if (!IsOnDemandService(service)) {
330         INIT_ERROR_CHECK(CreateServiceSocket(service) >= 0, return -1,
331             "service %s exit! create socket failed!", service->name);
332     }
333 
334     CreateServiceFile(service->fileCfg);
335     if ((service->attribute & SERVICE_ATTR_CONSOLE)) {
336         OpenConsole();
337     }
338 
339     PublishHoldFds(service);
340     INIT_CHECK_ONLY_ELOG(BindCpuCore(service) == SERVICE_SUCCESS,
341         "binding core number failed for service %s", service->name);
342 
343     // permissions
344     INIT_ERROR_CHECK(SetPerms(service) == SERVICE_SUCCESS, return -1,
345         "service %s exit! set perms failed! err %d.", service->name, errno);
346 
347     // write pid
348     INIT_ERROR_CHECK(WritePid(service) == SERVICE_SUCCESS, return -1,
349         "service %s exit! write pid failed!", service->name);
350     PluginExecCmdByName("setServiceContent", service->name);
351     return 0;
352 }
353 
EnterServiceSandbox(Service * service)354 void EnterServiceSandbox(Service *service)
355 {
356     INIT_ERROR_CHECK(InitServiceProperties(service) == 0, return, "Failed init service property");
357     if (service->importance != 0) {
358         if (setpriority(PRIO_PROCESS, 0, service->importance) != 0) {
359             INIT_LOGE("setpriority failed for %s, importance = %d, err=%d",
360                 service->name, service->importance, errno);
361                 _exit(0x7f); // 0x7f: user specified
362         }
363     }
364 #ifndef STARTUP_INIT_TEST
365     char *argv[] = { (char *)"/bin/sh", NULL };
366     INIT_CHECK_ONLY_ELOG(execv(argv[0], argv) == 0,
367         "service %s execv sh failed! err %d.", service->name, errno);
368     _exit(PROCESS_EXIT_CODE);
369 #endif
370 }
371 
AddUpdateList(ServiceArgs * args,char * updateList)372 static void AddUpdateList(ServiceArgs *args, char *updateList)
373 {
374     char** argvOrig = args->argv;
375     const int paramCount = 2; // -u updatelist
376     args->argv = (char **)malloc((args->count + paramCount) * sizeof(char *));
377     INIT_ERROR_CHECK(args->argv != NULL, return, "Failed to malloc for argv");
378     int i = 0;
379     for (; i < args->count + 1; ++i) {
380         if (i == args->count - 1) {
381             args->argv[i] = "-u";
382             args->argv[++i] = updateList;
383             break;
384         } else {
385             args->argv[i] = argvOrig[i];
386         }
387     }
388     args->argv[++i] = NULL;
389     args->count += paramCount;
390     free(argvOrig);
391 }
392 
CheckModuleUpdate(ServiceArgs * args)393 void CheckModuleUpdate(ServiceArgs *args)
394 {
395     INIT_LOGI("CheckModuleUpdate start");
396     void *handle = dlopen("libmodule_update.z.so", RTLD_NOW);
397     INIT_ERROR_CHECK(handle != NULL, return, "dlopen module update lib failed with error:%s", dlerror());
398     INIT_LOGI("dlopen success");
399     typedef char* (*ExtFunc)(int, char **);
400     ExtFunc func = (ExtFunc)dlsym(handle, "CheckModuleUpdate");
401     if (func == NULL) {
402         INIT_LOGE("dlsym get func failed with error:%s", dlerror());
403     } else {
404         char *updateList = func(args->count, args->argv);
405         INIT_LOGI("update list: %s", updateList);
406         if (updateList != NULL) {
407             AddUpdateList(args, updateList);
408         } else {
409             INIT_LOGW("no update list");
410         }
411     }
412     INIT_LOGI("CheckModuleUpdate end");
413 }
414 
415 #ifdef IS_DEBUG_VERSION
ServiceNeedDebug(char * name)416 static bool ServiceNeedDebug(char *name)
417 {
418     char nameValue[PARAM_VALUE_LEN_MAX] = {0};
419     unsigned int nameLen = PARAM_VALUE_LEN_MAX;
420     // specify process debugging: param set llvm.debug.service.name "service name"
421     if (SystemReadParam("llvm.debug.service.name", nameValue, &nameLen) == 0) {
422         if (strcmp(nameValue, name) == 0) {
423             return true;
424         }
425     }
426 
427     char debugValue[PARAM_VALUE_LEN_MAX] = {0};
428     unsigned int debugLen = PARAM_VALUE_LEN_MAX;
429     // multi process debugging: param set llvm.debug.service.all 1
430     if (SystemReadParam("llvm.debug.service.all", debugValue, &debugLen) == 0) {
431         if (strcmp(debugValue, "1") == 0) {
432             return true;
433         }
434     }
435     return false;
436 }
437 
IsDebuggableVersion(void)438 static bool IsDebuggableVersion(void)
439 {
440     char secureValue[PARAM_VALUE_LEN_MAX] = {0};
441     unsigned int secureLen = PARAM_VALUE_LEN_MAX;
442     char debugValue[PARAM_VALUE_LEN_MAX] = {0};
443     unsigned int debugLen = PARAM_VALUE_LEN_MAX;
444     // the image is debuggable only when secureValue is 0 and debugValue is 1
445     if (SystemReadParam("const.secure", secureValue, &secureLen) == 0 &&
446         SystemReadParam("const.debuggable", debugValue, &debugLen) == 0) {
447         if (strcmp(secureValue, "0") == 0 &&
448             strcmp(debugValue, "1") == 0) {
449             return true;
450         }
451     }
452     return false;
453 }
454 
CheckTraceStatus(void)455 static int32_t CheckTraceStatus(void)
456 {
457     int fd = open("/proc/self/status", O_RDONLY);
458     if (fd == -1) {
459         INIT_LOGE("lldb: open /proc/self/status error: %{public}d", errno);
460         return (-errno);
461     }
462 
463     char data[1024] = { 0 };  // 1024 data len
464     ssize_t dataNum = read(fd, data, sizeof(data));
465     if (close(fd) < 0) {
466         INIT_LOGE("lldb: close fd error: %{public}d", errno);
467         return (-errno);
468     }
469 
470     if (dataNum <= 0) {
471         INIT_LOGE("lldb: fail to read data");
472         return -1;
473     }
474 
475     const char* tracerPid = "TracerPid:\t";
476     data[1023] = '\0'; // 1023 data last position
477     char *traceStr = strstr(data, tracerPid);
478     if (traceStr == NULL) {
479         INIT_LOGE("lldb: fail to find %{public}s", tracerPid);
480         return -1;
481     }
482     char *separator = strchr(traceStr, '\n');
483     if (separator == NULL) {
484         INIT_LOGE("lldb: fail to find line break");
485         return -1;
486     }
487 
488     int len = separator - traceStr - strlen(tracerPid);
489     char pid = *(traceStr + strlen(tracerPid));
490     if (len > 1 || pid != '0') {
491         return 0;
492     }
493     return -1;
494 }
495 
WaitForDebugger(void)496 static int32_t WaitForDebugger(void)
497 {
498     uint32_t count = 0;
499     while (CheckTraceStatus() != 0) {
500         usleep(1000 * 100); // sleep 1000 * 100 microsecond
501         count++;
502         // remind users to connect to the debugger every 60 * 10 times
503         if (count % (10 * 60) == 0) {
504             INIT_LOGI("lldb: wait for debugger, please attach the process");
505             count = 0;
506         }
507     }
508     return 0;
509 }
510 #endif
511 
ServiceStart(Service * service)512 int ServiceStart(Service *service)
513 {
514     INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "start service failed! null ptr.");
515     INIT_ERROR_CHECK(service->pid <= 0, return SERVICE_SUCCESS, "Service %s already started", service->name);
516     INIT_ERROR_CHECK(service->pathArgs.count > 0,
517         return SERVICE_FAILURE, "start service %s pathArgs is NULL.", service->name);
518 
519     if (service->attribute & SERVICE_ATTR_INVALID) {
520         INIT_LOGE("start service %s invalid.", service->name);
521         return SERVICE_FAILURE;
522     }
523     struct stat pathStat = { 0 };
524     service->attribute &= (~(SERVICE_ATTR_NEED_RESTART | SERVICE_ATTR_NEED_STOP));
525     if (stat(service->pathArgs.argv[0], &pathStat) != 0) {
526         service->attribute |= SERVICE_ATTR_INVALID;
527         INIT_LOGE("start service %s invalid, please check %s.", service->name, service->pathArgs.argv[0]);
528         return SERVICE_FAILURE;
529     }
530 #ifndef OHOS_LITE
531     /*
532      * before service fork hooks
533      */
534     ServiceHookExecute(service->name, NULL, INIT_SERVICE_FORK_BEFORE);
535 #endif
536     int pid = fork();
537     if (pid == 0) {
538         // set selinux label by context
539         if (service->context.type != INIT_CONTEXT_MAIN) {
540             SetSubInitContext(&service->context, service->name);
541         }
542 
543         if (service->attribute & SERVICE_ATTR_MODULE_UPDATE) {
544             ServiceArgs* args = NULL;
545             if (service->extraArgs.argv != NULL && service->extraArgs.count > 0) {
546                 args = &service->extraArgs;
547             } else {
548                 args = &service->pathArgs;
549             }
550             CheckModuleUpdate(args);
551         }
552 #ifdef IS_DEBUG_VERSION
553         // only the image is debuggable and need debug, then wait for debugger
554         if (ServiceNeedDebug(service->name) && IsDebuggableVersion()) {
555             WaitForDebugger();
556         }
557 #endif
558         // fail must exit sub process
559         INIT_ERROR_CHECK(InitServiceProperties(service) == 0,
560             _exit(PROCESS_EXIT_CODE), "Failed init service property");
561         ServiceExec(service);
562         _exit(PROCESS_EXIT_CODE);
563     } else if (pid < 0) {
564         INIT_LOGE("start service %s fork failed!", service->name);
565         return SERVICE_FAILURE;
566     }
567     INIT_LOGI("Service %s(pid %d) started", service->name, pid);
568     service->pid = pid;
569     NotifyServiceChange(service, SERVICE_STARTED);
570 #ifndef OHOS_LITE
571     /*
572      * after service fork hooks
573      */
574     ServiceHookExecute(service->name, (const char *)&pid, INIT_SERVICE_FORK_AFTER);
575 #endif
576     return SERVICE_SUCCESS;
577 }
578 
ServiceStop(Service * service)579 int ServiceStop(Service *service)
580 {
581     INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "stop service failed! null ptr.");
582     NotifyServiceChange(service, SERVICE_STOPPING);
583     if (service->serviceJobs.jobsName[JOB_ON_STOP] != NULL) {
584         DoJobNow(service->serviceJobs.jobsName[JOB_ON_STOP]);
585     }
586     service->attribute &= ~SERVICE_ATTR_NEED_RESTART;
587     service->attribute |= SERVICE_ATTR_NEED_STOP;
588     if (service->pid <= 0) {
589         return SERVICE_SUCCESS;
590     }
591     CloseServiceSocket(service);
592     CloseServiceFile(service->fileCfg);
593     // Service stop means service is killed by init or command(i.e stop_service) or system is rebooting
594     // There is no reason still to hold fds
595     if (service->fdCount != 0) {
596         CloseServiceFds(service, true);
597     }
598 
599     if (IsServiceWithTimerEnabled(service)) {
600         ServiceStopTimer(service);
601     }
602     INIT_ERROR_CHECK(kill(service->pid, GetKillServiceSig(service->name)) == 0, return SERVICE_FAILURE,
603         "stop service %s pid %d failed! err %d.", service->name, service->pid, errno);
604     INIT_LOGI("stop service %s, pid %d.", service->name, service->pid);
605     service->pid = -1;
606     NotifyServiceChange(service, SERVICE_STOPPED);
607     return SERVICE_SUCCESS;
608 }
609 
CalculateCrashTime(Service * service,int crashTimeLimit,int crashCountLimit)610 static bool CalculateCrashTime(Service *service, int crashTimeLimit, int crashCountLimit)
611 {
612     INIT_ERROR_CHECK(service != NULL && crashTimeLimit > 0 && crashCountLimit > 0,
613         return false, "input params error.");
614     struct timespec curTime = {0};
615     (void)clock_gettime(CLOCK_MONOTONIC, &curTime);
616     struct timespec crashTime = {service->firstCrashTime, 0};
617     if (service->crashCnt == 0) {
618         service->firstCrashTime = curTime.tv_sec;
619         ++service->crashCnt;
620         if (service->crashCnt == crashCountLimit) {
621             return false;
622         }
623     } else if (IntervalTime(&crashTime, &curTime) > crashTimeLimit) {
624         service->firstCrashTime = curTime.tv_sec;
625         service->crashCnt = 1;
626     } else {
627         ++service->crashCnt;
628         if (service->crashCnt >= crashCountLimit) {
629             return false;
630         }
631     }
632     return true;
633 }
634 
ExecRestartCmd(Service * service)635 static int ExecRestartCmd(Service *service)
636 {
637     INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "Exec service failed! null ptr.");
638     if (service->restartArg == NULL) {
639         return SERVICE_SUCCESS;
640     }
641     for (int i = 0; i < service->restartArg->cmdNum; i++) {
642         INIT_LOGI("ExecRestartCmd cmdLine->cmdContent %s ", service->restartArg->cmds[i].cmdContent);
643         DoCmdByIndex(service->restartArg->cmds[i].cmdIndex, service->restartArg->cmds[i].cmdContent, NULL);
644     }
645     free(service->restartArg);
646     service->restartArg = NULL;
647     return SERVICE_SUCCESS;
648 }
649 
CheckServiceSocket(Service * service)650 static void CheckServiceSocket(Service *service)
651 {
652     if (service->socketCfg == NULL) {
653         return;
654     }
655     ServiceSocket *tmpSock = service->socketCfg;
656     while (tmpSock != NULL) {
657         if (tmpSock->sockFd <= 0) {
658             INIT_LOGE("Invalid socket %s for service", service->name);
659             tmpSock = tmpSock->next;
660         }
661         AddSocketWatcher(&tmpSock->watcher, service, tmpSock->sockFd);
662         tmpSock = tmpSock->next;
663     }
664     return;
665 }
666 
CheckOndemandService(Service * service)667 static void CheckOndemandService(Service *service)
668 {
669     CheckServiceSocket(service);
670     if (strcmp(service->name, "console") == 0) {
671         if (WatchConsoleDevice(service) < 0) {
672             INIT_LOGE("Failed to watch console service after it exit, mark console service invalid");
673             service->attribute |= SERVICE_ATTR_INVALID;
674         }
675     }
676 }
677 
ServiceReapHookExecute(Service * service)678 static void ServiceReapHookExecute(Service *service)
679 {
680 #ifndef OHOS_LITE
681     HookMgrExecute(GetBootStageHookMgr(), INIT_SERVICE_REAP, (void*)service, NULL);
682 #endif
683 }
684 
ServiceReap(Service * service)685 void ServiceReap(Service *service)
686 {
687     INIT_CHECK(service != NULL, return);
688     INIT_LOGI("Reap service %s, pid %d.", service->name, service->pid);
689     service->pid = -1;
690     NotifyServiceChange(service, SERVICE_STOPPED);
691 
692     if (service->attribute & SERVICE_ATTR_INVALID) {
693         INIT_LOGE("Reap service %s invalid.", service->name);
694         return;
695     }
696 
697     // If the service set timer
698     // which means the timer handler will start the service
699     // Init should not start it automatically.
700     INIT_CHECK(IsServiceWithTimerEnabled(service) == 0, return);
701 
702     if (!IsOnDemandService(service)) {
703         CloseServiceSocket(service);
704     }
705     CloseServiceFile(service->fileCfg);
706     // stopped by system-init itself, no need to restart even if it is not one-shot service
707     if (service->attribute & SERVICE_ATTR_NEED_STOP) {
708         service->attribute &= (~SERVICE_ATTR_NEED_STOP);
709         service->crashCnt = 0;
710         return;
711     }
712 
713     // for one-shot service
714     if (service->attribute & SERVICE_ATTR_ONCE) {
715         // no need to restart
716         if (!(service->attribute & SERVICE_ATTR_NEED_RESTART)) {
717             service->attribute &= (~SERVICE_ATTR_NEED_STOP);
718             return;
719         }
720         // the service could be restart even if it is one-shot service
721     }
722 
723     ServiceReapHookExecute(service);
724     // service no need to restart if it is an ondemand service.
725     if (IsOnDemandService(service)) {
726         CheckOndemandService(service);
727         return;
728     }
729     if (service->attribute & SERVICE_ATTR_CRITICAL) { // critical
730         if (!CalculateCrashTime(service, service->crashTime, service->crashCount)) {
731             INIT_LOGE("Critical service \" %s \" crashed %d times, rebooting system",
732                 service->name, service->crashCount);
733             ExecReboot("panic");
734         }
735     } else if (!(service->attribute & SERVICE_ATTR_NEED_RESTART)) {
736         if (!CalculateCrashTime(service, service->crashTime, service->crashCount)) {
737             INIT_LOGE("Service name=%s, crash %d times, no more start.", service->name, service->crashCount);
738             return;
739         }
740     }
741 
742     int ret = ExecRestartCmd(service);
743     INIT_CHECK_ONLY_ELOG(ret == SERVICE_SUCCESS, "Failed to exec restartArg for %s", service->name);
744 
745     if (service->serviceJobs.jobsName[JOB_ON_RESTART] != NULL) {
746         DoJobNow(service->serviceJobs.jobsName[JOB_ON_RESTART]);
747     }
748     ret = ServiceStart(service);
749     INIT_CHECK_ONLY_ELOG(ret == SERVICE_SUCCESS, "reap service %s start failed!", service->name);
750     service->attribute &= (~SERVICE_ATTR_NEED_RESTART);
751 }
752 
UpdaterServiceFds(Service * service,int * fds,size_t fdCount)753 int UpdaterServiceFds(Service *service, int *fds, size_t fdCount)
754 {
755     if (service == NULL || fds == NULL) {
756         INIT_LOGE("Invalid service info or fds");
757         return -1;
758     }
759 
760     if (fdCount == 0) {
761         INIT_LOGE("Update service fds with fdCount is 0, ignore.");
762         return 0;
763     }
764 
765     // if service->fds is NULL, allocate new memory to hold the fds
766     // else if service->fds is not NULL, we will try to override it.
767     // There are two cases:
768     // 1) service->fdCount != fdCount:
769     //  It is not easy to re-use the memory of service->fds, so we have to free the memory first
770     //  then re-allocate memory to store new fds
771     // 2) service->fdCount == fdCount
772     //  A situation we happy to meet, just override it.
773 
774     int ret = 0;
775     if (service->fdCount == fdCount) {
776         // case 2
777         CloseServiceFds(service, false);
778         if (memcpy_s(service->fds, sizeof(int) * (fdCount + 1), fds, sizeof(int) * fdCount) != 0) {
779             INIT_LOGE("Failed to copy fds to service");
780             // Something wrong happened, maybe service->fds is broken, clear it.
781             free(service->fds);
782             service->fds = NULL;
783             service->fdCount = 0;
784             ret = -1;
785         } else {
786             service->fdCount = fdCount;
787         }
788     } else {
789         if (service->fdCount > 0) {
790             // case 1
791             CloseServiceFds(service, true);
792         }
793         INIT_ERROR_CHECK(fdCount <= MAX_HOLD_FDS, return -1, "Invalid fdCount %d", fdCount);
794         service->fds = calloc(fdCount + 1, sizeof(int));
795         if (service->fds == NULL) {
796             INIT_LOGE("Service \' %s \' failed to allocate memory for fds", service->name);
797             ret = -1;
798         } else {
799             if (memcpy_s(service->fds, sizeof(int) * (fdCount + 1), fds, sizeof(int) * fdCount) != 0) {
800                 INIT_LOGE("Failed to copy fds to service");
801                 // Something wrong happened, maybe service->fds is broken, clear it.
802                 free(service->fds);
803                 service->fds = NULL;
804                 service->fdCount = 0;
805                 return -1;
806             } else {
807                 service->fdCount = fdCount;
808             }
809         }
810     }
811     INIT_LOGI("Hold fd for service \' %s \' done", service->name);
812     return ret;
813 }
814 
ServiceStopTimer(Service * service)815 void ServiceStopTimer(Service *service)
816 {
817     INIT_ERROR_CHECK(service != NULL, return, "Stop timer with invalid service");
818     if (IsServiceWithTimerEnabled(service)) {
819         // Stop timer first
820         if (service->timer) {
821             LE_StopTimer(LE_GetDefaultLoop(), service->timer);
822         }
823         service->timer = NULL;
824         DisableServiceTimer(service);
825     }
826 }
827 
ServiceTimerStartProcess(const TimerHandle handler,void * context)828 static void ServiceTimerStartProcess(const TimerHandle handler, void *context)
829 {
830     UNUSED(handler);
831     Service *service = (Service *)context;
832 
833     if (service == NULL) {
834         INIT_LOGE("Service timer process with invalid service");
835         return;
836     }
837 
838     // OK, service is ready to start.
839     // Before start the service, stop service timer.
840     // make sure it will not enter timer handler next time.
841     ServiceStopTimer(service);
842     int ret = ServiceStart(service);
843     if (ret != SERVICE_SUCCESS) {
844         INIT_LOGE("Start service \' %s \' in timer failed", service->name);
845     }
846 }
847 
ServiceStartTimer(Service * service,uint64_t timeout)848 void ServiceStartTimer(Service *service, uint64_t timeout)
849 {
850     bool oldTimerClean = false;
851     INIT_ERROR_CHECK(service != NULL, return, "Start timer with invalid service");
852     // If the service already set a timer.
853     // And a new request coming. close it and create a new one.
854     if (IsServiceWithTimerEnabled(service)) {
855         ServiceStopTimer(service);
856         oldTimerClean = true;
857     }
858     LE_STATUS status = LE_CreateTimer(LE_GetDefaultLoop(), &service->timer, ServiceTimerStartProcess,
859         (void *)service);
860     if (status != LE_SUCCESS) {
861         INIT_LOGE("Create service timer for service \' %s \' failed, status = %d", service->name, status);
862         if (oldTimerClean) {
863             INIT_LOGE("previous timer is cleared");
864         }
865         return;
866     }
867     status = LE_StartTimer(LE_GetDefaultLoop(), service->timer, timeout, 1);
868     INIT_ERROR_CHECK(status == LE_SUCCESS, return,
869         "Start service timer for service \' %s \' failed, status = %d", service->name, status);
870     EnableServiceTimer(service);
871 }
872