blob: 13bac092379cfefc9b4eb3db35ce0b8ecff47bb2 [file] [log] [blame]
Mark Salyzyn66ce3e02016-09-28 10:07:20 -07001/*
2 * Copyright (C) 2009-2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "Service"
18
San Mehatc41d1c82009-05-14 14:58:45 -070019#include <errno.h>
Mark Salyzyncfd5b082016-10-17 14:28:00 -070020#include <stdio.h>
Olivier Baillyb93e5812010-11-17 11:47:23 -080021#include <string.h>
Mark Salyzyncfd5b082016-10-17 14:28:00 -070022#include <unistd.h>
San Mehatc41d1c82009-05-14 14:58:45 -070023
San Mehatc41d1c82009-05-14 14:58:45 -070024#include <cutils/properties.h>
Mark Salyzyncfd5b082016-10-17 14:28:00 -070025#include <log/log.h>
Mark Salyzyn66ce3e02016-09-28 10:07:20 -070026#include <sysutils/ServiceManager.h>
San Mehatc41d1c82009-05-14 14:58:45 -070027
28ServiceManager::ServiceManager() {
29}
30
David 'Digit' Turneraf174f02011-01-17 02:22:22 +010031/* The service name should not exceed SERVICE_NAME_MAX to avoid
32 * some weird things. This is due to the fact that:
33 *
34 * - Starting a service is done by writing its name to the "ctl.start"
35 * system property. This triggers the init daemon to actually start
36 * the service for us.
37 *
38 * - Stopping the service is done by writing its name to "ctl.stop"
39 * in a similar way.
40 *
41 * - Reading the status of a service is done by reading the property
42 * named "init.svc.<name>"
43 *
44 * If strlen(<name>) > (PROPERTY_KEY_MAX-1)-9, then you can start/stop
45 * the service by writing to ctl.start/stop, but you won't be able to
46 * read its state due to the truncation of "init.svc.<name>" into a
47 * zero-terminated buffer of PROPERTY_KEY_MAX characters.
48 */
49#define SERVICE_NAME_MAX (PROPERTY_KEY_MAX-10)
50
51/* The maximum amount of time to wait for a service to start or stop,
52 * in micro-seconds (really an approximation) */
53#define SLEEP_MAX_USEC 2000000 /* 2 seconds */
54
55/* The minimal sleeping interval between checking for the service's state
56 * when looping for SLEEP_MAX_USEC */
57#define SLEEP_MIN_USEC 200000 /* 200 msec */
58
San Mehatc41d1c82009-05-14 14:58:45 -070059int ServiceManager::start(const char *name) {
David 'Digit' Turneraf174f02011-01-17 02:22:22 +010060 if (strlen(name) > SERVICE_NAME_MAX) {
61 SLOGE("Service name '%s' is too long", name);
62 return 0;
63 }
San Mehatc41d1c82009-05-14 14:58:45 -070064 if (isRunning(name)) {
San Mehat7e8529a2010-03-25 09:31:42 -070065 SLOGW("Service '%s' is already running", name);
San Mehatc41d1c82009-05-14 14:58:45 -070066 return 0;
67 }
68
San Mehat7e8529a2010-03-25 09:31:42 -070069 SLOGD("Starting service '%s'", name);
San Mehatc41d1c82009-05-14 14:58:45 -070070 property_set("ctl.start", name);
71
David 'Digit' Turneraf174f02011-01-17 02:22:22 +010072 int count = SLEEP_MAX_USEC;
73 while(count > 0) {
74 usleep(SLEEP_MIN_USEC);
75 count -= SLEEP_MIN_USEC;
San Mehatc41d1c82009-05-14 14:58:45 -070076 if (isRunning(name))
77 break;
78 }
David 'Digit' Turneraf174f02011-01-17 02:22:22 +010079 if (count <= 0) {
San Mehat7e8529a2010-03-25 09:31:42 -070080 SLOGW("Timed out waiting for service '%s' to start", name);
San Mehatc41d1c82009-05-14 14:58:45 -070081 errno = ETIMEDOUT;
82 return -1;
83 }
San Mehat7e8529a2010-03-25 09:31:42 -070084 SLOGD("Sucessfully started '%s'", name);
San Mehatc41d1c82009-05-14 14:58:45 -070085 return 0;
86}
87
88int ServiceManager::stop(const char *name) {
David 'Digit' Turneraf174f02011-01-17 02:22:22 +010089 if (strlen(name) > SERVICE_NAME_MAX) {
90 SLOGE("Service name '%s' is too long", name);
91 return 0;
92 }
San Mehatc41d1c82009-05-14 14:58:45 -070093 if (!isRunning(name)) {
San Mehat7e8529a2010-03-25 09:31:42 -070094 SLOGW("Service '%s' is already stopped", name);
San Mehatc41d1c82009-05-14 14:58:45 -070095 return 0;
96 }
97
San Mehat7e8529a2010-03-25 09:31:42 -070098 SLOGD("Stopping service '%s'", name);
San Mehatc41d1c82009-05-14 14:58:45 -070099 property_set("ctl.stop", name);
100
David 'Digit' Turneraf174f02011-01-17 02:22:22 +0100101 int count = SLEEP_MAX_USEC;
102 while(count > 0) {
103 usleep(SLEEP_MIN_USEC);
104 count -= SLEEP_MIN_USEC;
San Mehatc41d1c82009-05-14 14:58:45 -0700105 if (!isRunning(name))
106 break;
107 }
108
David 'Digit' Turneraf174f02011-01-17 02:22:22 +0100109 if (count <= 0) {
San Mehat7e8529a2010-03-25 09:31:42 -0700110 SLOGW("Timed out waiting for service '%s' to stop", name);
San Mehatc41d1c82009-05-14 14:58:45 -0700111 errno = ETIMEDOUT;
112 return -1;
113 }
David 'Digit' Turneraf174f02011-01-17 02:22:22 +0100114 SLOGD("Successfully stopped '%s'", name);
San Mehatc41d1c82009-05-14 14:58:45 -0700115 return 0;
116}
117
118bool ServiceManager::isRunning(const char *name) {
119 char propVal[PROPERTY_VALUE_MAX];
David 'Digit' Turneraf174f02011-01-17 02:22:22 +0100120 char propName[PROPERTY_KEY_MAX];
121 int ret;
San Mehatc41d1c82009-05-14 14:58:45 -0700122
David 'Digit' Turneraf174f02011-01-17 02:22:22 +0100123 ret = snprintf(propName, sizeof(propName), "init.svc.%s", name);
124 if (ret > (int)sizeof(propName)-1) {
125 SLOGD("Service name '%s' is too long", name);
126 return false;
127 }
San Mehatc41d1c82009-05-14 14:58:45 -0700128
129 if (property_get(propName, propVal, NULL)) {
130 if (!strcmp(propVal, "running"))
131 return true;
132 }
133 return false;
134}