• 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 <errno.h>
17 #include <fcntl.h>
18 #include <signal.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #ifdef __MUSL__
22 #include <stropts.h>
23 #endif
24 #include <sys/capability.h>
25 #include <sys/ioctl.h>
26 #include <sys/param.h>
27 #include <sys/resource.h>
28 #include <sys/stat.h>
29 #include <time.h>
30 #include <unistd.h>
31 
32 #include "init.h"
33 #include "init_adapter.h"
34 #include "init_cmds.h"
35 #include "init_cmdexecutor.h"
36 #include "init_log.h"
37 #include "init_cmdexecutor.h"
38 #include "init_jobs_internal.h"
39 #include "init_service.h"
40 #include "init_service_manager.h"
41 #include "init_service_socket.h"
42 #include "init_utils.h"
43 #include "fd_holder_internal.h"
44 #include "loop_event.h"
45 #include "securec.h"
46 #include "service_control.h"
47 
48 #ifndef OHOS_LITE
49 #include "hookmgr.h"
50 #include "bootstage.h"
51 #endif
52 
53 #ifdef WITH_SECCOMP
54 #define APPSPAWN_NAME ("appspawn")
55 #define NWEBSPAWN_NAME ("nwebspawn")
56 #define SA_MAIN_PATH ("/system/bin/sa_main")
57 #endif
58 
59 #ifndef TIOCSCTTY
60 #define TIOCSCTTY 0x540E
61 #endif
62 
SetAllAmbientCapability(void)63 static int SetAllAmbientCapability(void)
64 {
65     for (int i = 0; i <= CAP_LAST_CAP; ++i) {
66         if (SetAmbientCapability(i) != 0) {
67             return SERVICE_FAILURE;
68         }
69     }
70     return SERVICE_SUCCESS;
71 }
72 
SetSystemSeccompPolicy(const Service * service)73 static void SetSystemSeccompPolicy(const Service *service)
74 {
75 #ifdef WITH_SECCOMP
76     if (strncmp(APPSPAWN_NAME, service->name, strlen(APPSPAWN_NAME)) \
77         && strncmp(NWEBSPAWN_NAME, service->name, strlen(NWEBSPAWN_NAME))
78         && !strncmp(SA_MAIN_PATH, service->pathArgs.argv[0], strlen(SA_MAIN_PATH))) {
79         PluginExecCmdByName("SetSeccompPolicy", "start");
80     }
81 #endif
82 }
83 
84 #ifndef OHOS_LITE
85 /**
86  * service Hooking
87  */
ServiceHookWrapper(const HOOK_INFO * hookInfo,void * executionContext)88 static int ServiceHookWrapper(const HOOK_INFO *hookInfo, void *executionContext)
89 {
90     SERVICE_INFO_CTX *serviceContext = (SERVICE_INFO_CTX *)executionContext;
91     ServiceHook realHook = (ServiceHook)hookInfo->hookCookie;
92 
93     realHook(serviceContext);
94     return 0;
95 };
96 
InitAddServiceHook(ServiceHook hook,int hookState)97 int InitAddServiceHook(ServiceHook hook, int hookState)
98 {
99     HOOK_INFO info;
100 
101     info.stage = hookState;
102     info.prio = 0;
103     info.hook = ServiceHookWrapper;
104     info.hookCookie = (void *)hook;
105 
106     return HookMgrAddEx(GetBootStageHookMgr(), &info);
107 }
108 
109 /**
110  * service hooking execute
111  */
ServiceHookExecute(const char * serviceName,const char * info,int stage)112 static void ServiceHookExecute(const char *serviceName, const char *info, int stage)
113 {
114     SERVICE_INFO_CTX context;
115 
116     context.serviceName = serviceName;
117     context.reserved = info;
118 
119     (void)HookMgrExecute(GetBootStageHookMgr(), stage, (void *)(&context), NULL);
120 }
121 #endif
122 
SetPerms(const Service * service)123 static int SetPerms(const Service *service)
124 {
125     INIT_CHECK_RETURN_VALUE(KeepCapability() == 0, SERVICE_FAILURE);
126 
127     if (service->servPerm.gIDCnt == 0) {
128         // use uid as gid
129         INIT_ERROR_CHECK(setgid(service->servPerm.uID) == 0, return SERVICE_FAILURE,
130             "SetPerms, setgid for %s failed. %d", service->name, errno);
131     }
132     if (service->servPerm.gIDCnt > 0) {
133         INIT_ERROR_CHECK(setgid(service->servPerm.gIDArray[0]) == 0, return SERVICE_FAILURE,
134             "SetPerms, setgid for %s failed. %d", service->name, errno);
135     }
136     if (service->servPerm.gIDCnt > 1) {
137         INIT_ERROR_CHECK(setgroups(service->servPerm.gIDCnt - 1, (const gid_t *)&service->servPerm.gIDArray[1]) == 0,
138             return SERVICE_FAILURE,
139             "SetPerms, setgroups failed. errno = %d, gIDCnt=%d", errno, service->servPerm.gIDCnt);
140     }
141     if (service->servPerm.uID != 0) {
142         if (setuid(service->servPerm.uID) != 0) {
143             INIT_LOGE("setuid of service: %s failed, uid = %d", service->name, service->servPerm.uID);
144             return SERVICE_FAILURE;
145         }
146     }
147 
148     struct __user_cap_header_struct capHeader;
149     capHeader.version = _LINUX_CAPABILITY_VERSION_3;
150     capHeader.pid = 0;
151     struct __user_cap_data_struct capData[CAP_NUM] = {};
152     for (unsigned int i = 0; i < service->servPerm.capsCnt; ++i) {
153         if (service->servPerm.caps[i] == FULL_CAP) {
154             for (int j = 0; j < CAP_NUM; ++j) {
155                 capData[j].effective = FULL_CAP;
156                 capData[j].permitted = FULL_CAP;
157                 capData[j].inheritable = FULL_CAP;
158             }
159             break;
160         }
161         capData[CAP_TO_INDEX(service->servPerm.caps[i])].effective |= CAP_TO_MASK(service->servPerm.caps[i]);
162         capData[CAP_TO_INDEX(service->servPerm.caps[i])].permitted |= CAP_TO_MASK(service->servPerm.caps[i]);
163         capData[CAP_TO_INDEX(service->servPerm.caps[i])].inheritable |= CAP_TO_MASK(service->servPerm.caps[i]);
164     }
165 
166     INIT_ERROR_CHECK(capset(&capHeader, capData) == 0, return SERVICE_FAILURE,
167         "capset failed for service: %s, error: %d", service->name, errno);
168     for (unsigned int i = 0; i < service->servPerm.capsCnt; ++i) {
169         if (service->servPerm.caps[i] == FULL_CAP) {
170             return SetAllAmbientCapability();
171         }
172         INIT_ERROR_CHECK(SetAmbientCapability(service->servPerm.caps[i]) == 0, return SERVICE_FAILURE,
173             "SetAmbientCapability failed for service: %s", service->name);
174     }
175 #ifndef OHOS_LITE
176     /*
177      * service set Perms hooks
178      */
179     ServiceHookExecute(service->name, NULL, INIT_SERVICE_SET_PERMS);
180 #endif
181     return SERVICE_SUCCESS;
182 }
183 
WritePid(const Service * service)184 static int WritePid(const Service *service)
185 {
186     const int maxPidStrLen = 50;
187     char pidString[maxPidStrLen];
188     pid_t childPid = getpid();
189     int len = snprintf_s(pidString, maxPidStrLen, maxPidStrLen - 1, "%d", childPid);
190     INIT_ERROR_CHECK(len > 0, return SERVICE_FAILURE, "Failed to format pid for service %s", service->name);
191     for (int i = 0; i < service->writePidArgs.count; i++) {
192         if (service->writePidArgs.argv[i] == NULL) {
193             continue;
194         }
195         FILE *fd = NULL;
196         char *realPath = GetRealPath(service->writePidArgs.argv[i]);
197         if (realPath != NULL) {
198             fd = fopen(realPath, "wb");
199         } else {
200             fd = fopen(service->writePidArgs.argv[i], "wb");
201         }
202         if (fd != NULL) {
203             INIT_CHECK_ONLY_ELOG((int)fwrite(pidString, 1, len, fd) == len,
204                 "Failed to write %s pid:%s", service->writePidArgs.argv[i], pidString);
205             (void)fclose(fd);
206         } else {
207             INIT_LOGE("Failed to open %s.", service->writePidArgs.argv[i]);
208         }
209         if (realPath != NULL) {
210             free(realPath);
211         }
212         INIT_LOGV("ServiceStart writepid filename=%s, childPid=%s, ok", service->writePidArgs.argv[i], pidString);
213     }
214     return SERVICE_SUCCESS;
215 }
216 
CloseServiceFds(Service * service,bool needFree)217 void CloseServiceFds(Service *service, bool needFree)
218 {
219     if (service == NULL) {
220         return;
221     }
222 
223     INIT_LOGI("Closing service \' %s \' fds", service->name);
224     // fdCount > 0, There is no reason fds is NULL
225     if (service->fdCount != 0) {
226         size_t fdCount = service->fdCount;
227         int *fds = service->fds;
228         for (size_t i = 0; i < fdCount; i++) {
229             INIT_LOGV("Closing fd: %d", fds[i]);
230             close(fds[i]);
231             fds[i] = -1;
232         }
233     }
234     service->fdCount = 0;
235     if (needFree && service->fds != NULL) {
236         free(service->fds);
237         service->fds = NULL;
238     }
239 }
240 
PublishHoldFds(Service * service)241 static void PublishHoldFds(Service *service)
242 {
243     INIT_ERROR_CHECK(service != NULL, return, "Publish hold fds with invalid service");
244     char fdBuffer[MAX_FD_HOLDER_BUFFER] = {};
245     if (service->fdCount > 0 && service->fds != NULL) {
246         size_t pos = 0;
247         for (size_t i = 0; i < service->fdCount; i++) {
248             int fd = dup(service->fds[i]);
249             if (fd < 0) {
250                 INIT_LOGE("Duplicate file descriptors of Service \' %s \' failed. err = %d", service->name, errno);
251                 continue;
252             }
253             INIT_ERROR_CHECK(!(snprintf_s((char *)fdBuffer + pos, sizeof(fdBuffer) - pos, sizeof(fdBuffer) - 1,
254                 "%d ", fd) < 0), return, "snprintf_s failed err=%d", errno);
255             pos = strlen(fdBuffer);
256         }
257         fdBuffer[pos - 1] = '\0'; // Remove last ' '
258         INIT_LOGI("fd buffer: [%s]", fdBuffer);
259         char envName[MAX_BUFFER_LEN] = {};
260         INIT_ERROR_CHECK(!(snprintf_s(envName, MAX_BUFFER_LEN, MAX_BUFFER_LEN - 1, ENV_FD_HOLD_PREFIX"%s",
261             service->name) < 0), return, "snprintf_s failed err=%d", errno);
262         INIT_CHECK_ONLY_ELOG(!(setenv(envName, fdBuffer, 1) < 0), "Failed to set env %s", envName);
263         INIT_LOGI("File descriptors of Service \' %s \' published", service->name);
264     }
265 }
266 
BindCpuCore(Service * service)267 static int BindCpuCore(Service *service)
268 {
269     if (service == NULL || service->cpuSet == NULL) {
270         return SERVICE_SUCCESS;
271     }
272     if (CPU_COUNT(service->cpuSet) == 0) {
273         return SERVICE_SUCCESS;
274     }
275 #ifndef __LITEOS_A__
276     int pid = getpid();
277     INIT_ERROR_CHECK(sched_setaffinity(pid, sizeof(cpu_set_t), service->cpuSet) == 0,
278         return SERVICE_FAILURE, "%s set affinity between process(pid=%d) with CPU's core failed", service->name, pid);
279     INIT_LOGI("%s set affinity between process(pid=%d) with CPU's core successfully", service->name, pid);
280 #endif
281     return SERVICE_SUCCESS;
282 }
283 
ClearEnvironment(Service * service)284 static void ClearEnvironment(Service *service)
285 {
286     if (strcmp(service->name, "appspawn") != 0 && strcmp(service->name, "nwebspawn") != 0) {
287         sigset_t mask;
288         sigemptyset(&mask);
289         sigaddset(&mask, SIGCHLD);
290         sigaddset(&mask, SIGTERM);
291         sigprocmask(SIG_UNBLOCK, &mask, NULL);
292     }
293     return;
294 }
295 
InitServiceProperties(Service * service)296 static int InitServiceProperties(Service *service)
297 {
298     INIT_ERROR_CHECK(service != NULL, return -1, "Invalid parameter.");
299     SetServiceEnterSandbox(service->pathArgs.argv[0], service->attribute);
300     INIT_CHECK_ONLY_ELOG(SetAccessToken(service) == SERVICE_SUCCESS,
301         "Set service %s access token failed", service->name);
302     // deal start job
303     if (service->serviceJobs.jobsName[JOB_ON_START] != NULL) {
304         DoJobNow(service->serviceJobs.jobsName[JOB_ON_START]);
305     }
306     ClearEnvironment(service);
307     if (!IsOnDemandService(service)) {
308         INIT_ERROR_CHECK(CreateServiceSocket(service) >= 0, return -1,
309             "service %s exit! create socket failed!", service->name);
310     }
311 
312     CreateServiceFile(service->fileCfg);
313     if ((service->attribute & SERVICE_ATTR_CONSOLE)) {
314         OpenConsole();
315     }
316 
317     PublishHoldFds(service);
318     INIT_CHECK_ONLY_ELOG(BindCpuCore(service) == SERVICE_SUCCESS,
319         "binding core number failed for service %s", service->name);
320 
321     SetSystemSeccompPolicy(service);
322 
323     // permissions
324     INIT_ERROR_CHECK(SetPerms(service) == SERVICE_SUCCESS, return -1,
325         "service %s exit! set perms failed! err %d.", service->name, errno);
326 
327     // write pid
328     INIT_ERROR_CHECK(WritePid(service) == SERVICE_SUCCESS, return -1,
329         "service %s exit! write pid failed!", service->name);
330     PluginExecCmdByName("setServiceContent", service->name);
331     return 0;
332 }
333 
EnterServiceSandbox(Service * service)334 void EnterServiceSandbox(Service *service)
335 {
336     INIT_ERROR_CHECK(InitServiceProperties(service) == 0, return, "Failed init service property");
337     if (service->importance != 0) {
338         if (setpriority(PRIO_PROCESS, 0, service->importance) != 0) {
339             INIT_LOGE("setpriority failed for %s, importance = %d, err=%d",
340                 service->name, service->importance, errno);
341                 _exit(0x7f); // 0x7f: user specified
342         }
343     }
344 #ifndef STARTUP_INIT_TEST
345     char *argv[] = { (char *)"/bin/sh", NULL };
346     INIT_CHECK_ONLY_ELOG(execv(argv[0], argv) == 0,
347         "service %s execv sh failed! err %d.", service->name, errno);
348     _exit(PROCESS_EXIT_CODE);
349 #endif
350 }
351 
ServiceStart(Service * service)352 int ServiceStart(Service *service)
353 {
354     INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "start service failed! null ptr.");
355     INIT_ERROR_CHECK(service->pid <= 0, return SERVICE_SUCCESS, "Service %s already started", service->name);
356     INIT_ERROR_CHECK(service->pathArgs.count > 0,
357         return SERVICE_FAILURE, "start service %s pathArgs is NULL.", service->name);
358 
359     if (service->attribute & SERVICE_ATTR_INVALID) {
360         INIT_LOGE("start service %s invalid.", service->name);
361         return SERVICE_FAILURE;
362     }
363     struct stat pathStat = { 0 };
364     service->attribute &= (~(SERVICE_ATTR_NEED_RESTART | SERVICE_ATTR_NEED_STOP));
365     if (stat(service->pathArgs.argv[0], &pathStat) != 0) {
366         service->attribute |= SERVICE_ATTR_INVALID;
367         INIT_LOGE("start service %s invalid, please check %s.", service->name, service->pathArgs.argv[0]);
368         return SERVICE_FAILURE;
369     }
370 #ifndef OHOS_LITE
371     /*
372      * before service fork hooks
373      */
374     ServiceHookExecute(service->name, NULL, INIT_SERVICE_FORK_BEFORE);
375 #endif
376     int pid = fork();
377     if (pid == 0) {
378         // fail must exit sub process
379         INIT_ERROR_CHECK(InitServiceProperties(service) == 0,
380             _exit(PROCESS_EXIT_CODE), "Failed init service property");
381         ServiceExec(service);
382         _exit(PROCESS_EXIT_CODE);
383     } else if (pid < 0) {
384         INIT_LOGE("start service %s fork failed!", service->name);
385         return SERVICE_FAILURE;
386     }
387     INIT_LOGI("Service %s(pid %d) started", service->name, pid);
388     service->pid = pid;
389     NotifyServiceChange(service, SERVICE_STARTED);
390 #ifndef OHOS_LITE
391     /*
392      * after service fork hooks
393      */
394     ServiceHookExecute(service->name, (const char *)&pid, INIT_SERVICE_FORK_AFTER);
395 #endif
396     return SERVICE_SUCCESS;
397 }
398 
ServiceStop(Service * service)399 int ServiceStop(Service *service)
400 {
401     INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "stop service failed! null ptr.");
402     if (service->serviceJobs.jobsName[JOB_ON_STOP] != NULL) {
403         DoJobNow(service->serviceJobs.jobsName[JOB_ON_STOP]);
404     }
405     service->attribute &= ~SERVICE_ATTR_NEED_RESTART;
406     service->attribute |= SERVICE_ATTR_NEED_STOP;
407     if (service->pid <= 0) {
408         return SERVICE_SUCCESS;
409     }
410     CloseServiceSocket(service);
411     CloseServiceFile(service->fileCfg);
412     // Service stop means service is killed by init or command(i.e stop_service) or system is rebooting
413     // There is no reason still to hold fds
414     if (service->fdCount != 0) {
415         CloseServiceFds(service, true);
416     }
417 
418     if (IsServiceWithTimerEnabled(service)) {
419         ServiceStopTimer(service);
420     }
421     INIT_ERROR_CHECK(kill(service->pid, GetKillServiceSig(service->name)) == 0, return SERVICE_FAILURE,
422         "stop service %s pid %d failed! err %d.", service->name, service->pid, errno);
423     NotifyServiceChange(service, SERVICE_STOPPING);
424     INIT_LOGI("stop service %s, pid %d.", service->name, service->pid);
425     service->pid = -1;
426     NotifyServiceChange(service, SERVICE_STOPPED);
427     return SERVICE_SUCCESS;
428 }
429 
CalculateCrashTime(Service * service,int crashTimeLimit,int crashCountLimit)430 static bool CalculateCrashTime(Service *service, int crashTimeLimit, int crashCountLimit)
431 {
432     INIT_ERROR_CHECK(service != NULL && crashTimeLimit > 0 && crashCountLimit > 0,
433         return false, "input params error.");
434     time_t curTime = time(NULL);
435     if (service->crashCnt == 0) {
436         service->firstCrashTime = curTime;
437         ++service->crashCnt;
438         if (service->crashCnt == crashCountLimit) {
439             return false;
440         }
441     } else if (difftime(curTime, service->firstCrashTime) > crashTimeLimit) {
442         service->firstCrashTime = curTime;
443         service->crashCnt = 1;
444     } else {
445         ++service->crashCnt;
446         if (service->crashCnt >= crashCountLimit) {
447             return false;
448         }
449     }
450     return true;
451 }
452 
ExecRestartCmd(Service * service)453 static int ExecRestartCmd(Service *service)
454 {
455     INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "Exec service failed! null ptr.");
456     if (service->restartArg == NULL) {
457         return SERVICE_SUCCESS;
458     }
459     for (int i = 0; i < service->restartArg->cmdNum; i++) {
460         INIT_LOGI("ExecRestartCmd cmdLine->cmdContent %s ", service->restartArg->cmds[i].cmdContent);
461         DoCmdByIndex(service->restartArg->cmds[i].cmdIndex, service->restartArg->cmds[i].cmdContent);
462     }
463     free(service->restartArg);
464     service->restartArg = NULL;
465     return SERVICE_SUCCESS;
466 }
467 
CheckServiceSocket(Service * service)468 static void CheckServiceSocket(Service *service)
469 {
470     if (service->socketCfg == NULL) {
471         return;
472     }
473     ServiceSocket *tmpSock = service->socketCfg;
474     while (tmpSock != NULL) {
475         if (tmpSock->sockFd <= 0) {
476             INIT_LOGE("Invalid socket %s for service", service->name);
477             tmpSock = tmpSock->next;
478         }
479         SocketAddWatcher(&tmpSock->watcher, service, tmpSock->sockFd);
480         tmpSock = tmpSock->next;
481     }
482     return;
483 }
484 
CheckOndemandService(Service * service)485 static void CheckOndemandService(Service *service)
486 {
487     CheckServiceSocket(service);
488     if (strcmp(service->name, "console") == 0) {
489         if (WatchConsoleDevice(service) < 0) {
490             INIT_LOGE("Failed to watch console service after it exit, mark console service invalid");
491             service->attribute |= SERVICE_ATTR_INVALID;
492         }
493     }
494 }
495 
ServiceReap(Service * service)496 void ServiceReap(Service *service)
497 {
498     INIT_CHECK(service != NULL, return);
499     INIT_LOGI("Reap service %s, pid %d.", service->name, service->pid);
500     service->pid = -1;
501     NotifyServiceChange(service, SERVICE_STOPPED);
502 
503     if (service->attribute & SERVICE_ATTR_INVALID) {
504         INIT_LOGE("Reap service %s invalid.", service->name);
505         return;
506     }
507 
508     // If the service set timer
509     // which means the timer handler will start the service
510     // Init should not start it automatically.
511     INIT_CHECK(IsServiceWithTimerEnabled(service) == 0, return);
512 
513     if (!IsOnDemandService(service)) {
514         CloseServiceSocket(service);
515     }
516     CloseServiceFile(service->fileCfg);
517     // stopped by system-init itself, no need to restart even if it is not one-shot service
518     if (service->attribute & SERVICE_ATTR_NEED_STOP) {
519         service->attribute &= (~SERVICE_ATTR_NEED_STOP);
520         service->crashCnt = 0;
521         return;
522     }
523 
524     // for one-shot service
525     if (service->attribute & SERVICE_ATTR_ONCE) {
526         // no need to restart
527         if (!(service->attribute & SERVICE_ATTR_NEED_RESTART)) {
528             service->attribute &= (~SERVICE_ATTR_NEED_STOP);
529             return;
530         }
531         // the service could be restart even if it is one-shot service
532     }
533 
534     if (service->attribute & SERVICE_ATTR_CRITICAL) { // critical
535         if (!CalculateCrashTime(service, service->crashTime, service->crashCount)) {
536             INIT_LOGE("Critical service \" %s \" crashed %d times, rebooting system",
537                 service->name, service->crashCount);
538             ExecReboot("panic");
539         }
540     } else if (!(service->attribute & SERVICE_ATTR_NEED_RESTART)) {
541         if (!CalculateCrashTime(service, service->crashTime, service->crashCount)) {
542             INIT_LOGE("Service name=%s, crash %d times, no more start.", service->name, service->crashCount);
543             return;
544         }
545     }
546     // service no need to restart if it is an ondemand service.
547     if (IsOnDemandService(service)) {
548         CheckOndemandService(service);
549         return;
550     }
551 
552     int ret = ExecRestartCmd(service);
553     INIT_CHECK_ONLY_ELOG(ret == SERVICE_SUCCESS, "Failed to exec restartArg for %s", service->name);
554 
555     if (service->serviceJobs.jobsName[JOB_ON_RESTART] != NULL) {
556         DoJobNow(service->serviceJobs.jobsName[JOB_ON_RESTART]);
557     }
558     ret = ServiceStart(service);
559     INIT_CHECK_ONLY_ELOG(ret == SERVICE_SUCCESS, "reap service %s start failed!", service->name);
560     service->attribute &= (~SERVICE_ATTR_NEED_RESTART);
561 }
562 
UpdaterServiceFds(Service * service,int * fds,size_t fdCount)563 int UpdaterServiceFds(Service *service, int *fds, size_t fdCount)
564 {
565     if (service == NULL) {
566         INIT_LOGE("Invalid service info");
567         return -1;
568     }
569 
570     if (fdCount == 0) {
571         INIT_LOGE("Update service fds with fdCount is 0, ignore.");
572         return 0;
573     }
574 
575     // if service->fds is NULL, allocate new memory to hold the fds
576     // else if service->fds is not NULL, we will try to override it.
577     // There are two cases:
578     // 1) service->fdCount != fdCount:
579     //  It is not easy to re-use the memory of service->fds, so we have to free the memory first
580     //  then re-allocate memory to store new fds
581     // 2) service->fdCount == fdCount
582     //  A situation we happy to meet, just override it.
583 
584     int ret = 0;
585     if (service->fdCount == fdCount) {
586         // case 2
587         CloseServiceFds(service, false);
588         if (memcpy_s(service->fds, sizeof(int) * (fdCount + 1), fds, sizeof(int) * fdCount) != 0) {
589             INIT_LOGE("Failed to copy fds to service");
590             // Something wrong happened, maybe service->fds is broken, clear it.
591             free(service->fds);
592             service->fds = NULL;
593             service->fdCount = 0;
594             ret = -1;
595         } else {
596             service->fdCount = fdCount;
597         }
598     } else {
599         if (service->fdCount > 0) {
600             // case 1
601             CloseServiceFds(service, true);
602         }
603         service->fds = calloc(fdCount + 1, sizeof(int));
604         if (service->fds == NULL) {
605             INIT_LOGE("Service \' %s \' failed to allocate memory for fds", service->name);
606             ret = -1;
607         } else {
608             if (memcpy_s(service->fds, sizeof(int) * (fdCount + 1), fds, sizeof(int) * fdCount) != 0) {
609                 INIT_LOGE("Failed to copy fds to service");
610                 // Something wrong happened, maybe service->fds is broken, clear it.
611                 free(service->fds);
612                 service->fds = NULL;
613                 service->fdCount = 0;
614                 return -1;
615             } else {
616                 service->fdCount = fdCount;
617             }
618         }
619     }
620     INIT_LOGI("Hold fd for service \' %s \' done", service->name);
621     return ret;
622 }
623 
ServiceStopTimer(Service * service)624 void ServiceStopTimer(Service *service)
625 {
626     INIT_ERROR_CHECK(service != NULL, return, "Stop timer with invalid service");
627     if (IsServiceWithTimerEnabled(service)) {
628         // Stop timer first
629         if (service->timer) {
630             LE_StopTimer(LE_GetDefaultLoop(), service->timer);
631         }
632         service->timer = NULL;
633         DisableServiceTimer(service);
634     }
635 }
636 
ServiceTimerStartProcess(const TimerHandle handler,void * context)637 static void ServiceTimerStartProcess(const TimerHandle handler, void *context)
638 {
639     UNUSED(handler);
640     Service *service = (Service *)context;
641 
642     if (service == NULL) {
643         INIT_LOGE("Service timer process with invalid service");
644         return;
645     }
646 
647     // OK, service is ready to start.
648     // Before start the service, stop service timer.
649     // make sure it will not enter timer handler next time.
650     ServiceStopTimer(service);
651     int ret = ServiceStart(service);
652     if (ret != SERVICE_SUCCESS) {
653         INIT_LOGE("Start service \' %s \' in timer failed", service->name);
654     }
655 }
656 
ServiceStartTimer(Service * service,uint64_t timeout)657 void ServiceStartTimer(Service *service, uint64_t timeout)
658 {
659     bool oldTimerClean = false;
660     INIT_ERROR_CHECK(service != NULL, return, "Start timer with invalid service");
661     // If the service already set a timer.
662     // And a new request coming. close it and create a new one.
663     if (IsServiceWithTimerEnabled(service)) {
664         ServiceStopTimer(service);
665         oldTimerClean = true;
666     }
667     LE_STATUS status = LE_CreateTimer(LE_GetDefaultLoop(), &service->timer, ServiceTimerStartProcess,
668         (void *)service);
669     if (status != LE_SUCCESS) {
670         INIT_LOGE("Create service timer for service \' %s \' failed, status = %d", service->name, status);
671         if (oldTimerClean) {
672             INIT_LOGE("previous timer is cleared");
673         }
674         return;
675     }
676     status = LE_StartTimer(LE_GetDefaultLoop(), service->timer, timeout, 1);
677     INIT_ERROR_CHECK(status == LE_SUCCESS, return,
678         "Start service timer for service \' %s \' failed, status = %d", service->name, status);
679     EnableServiceTimer(service);
680 }
681