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