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