blob: 41ac1dd31e3ea0f9e75d4dc05125071f3c0bdf0b [file] [log] [blame]
San Mehatc41d1c82009-05-14 14:58:45 -07001#include <errno.h>
Olivier Baillyb93e5812010-11-17 11:47:23 -08002#include <string.h>
San Mehatc41d1c82009-05-14 14:58:45 -07003
4#include <sysutils/ServiceManager.h>
5
6#define LOG_TAG "Service"
7#include <cutils/log.h>
8#include <cutils/properties.h>
9
10ServiceManager::ServiceManager() {
11}
12
David 'Digit' Turneraf174f02011-01-17 02:22:22 +010013/* The service name should not exceed SERVICE_NAME_MAX to avoid
14 * some weird things. This is due to the fact that:
15 *
16 * - Starting a service is done by writing its name to the "ctl.start"
17 * system property. This triggers the init daemon to actually start
18 * the service for us.
19 *
20 * - Stopping the service is done by writing its name to "ctl.stop"
21 * in a similar way.
22 *
23 * - Reading the status of a service is done by reading the property
24 * named "init.svc.<name>"
25 *
26 * If strlen(<name>) > (PROPERTY_KEY_MAX-1)-9, then you can start/stop
27 * the service by writing to ctl.start/stop, but you won't be able to
28 * read its state due to the truncation of "init.svc.<name>" into a
29 * zero-terminated buffer of PROPERTY_KEY_MAX characters.
30 */
31#define SERVICE_NAME_MAX (PROPERTY_KEY_MAX-10)
32
33/* The maximum amount of time to wait for a service to start or stop,
34 * in micro-seconds (really an approximation) */
35#define SLEEP_MAX_USEC 2000000 /* 2 seconds */
36
37/* The minimal sleeping interval between checking for the service's state
38 * when looping for SLEEP_MAX_USEC */
39#define SLEEP_MIN_USEC 200000 /* 200 msec */
40
San Mehatc41d1c82009-05-14 14:58:45 -070041int ServiceManager::start(const char *name) {
David 'Digit' Turneraf174f02011-01-17 02:22:22 +010042 if (strlen(name) > SERVICE_NAME_MAX) {
43 SLOGE("Service name '%s' is too long", name);
44 return 0;
45 }
San Mehatc41d1c82009-05-14 14:58:45 -070046 if (isRunning(name)) {
San Mehat7e8529a2010-03-25 09:31:42 -070047 SLOGW("Service '%s' is already running", name);
San Mehatc41d1c82009-05-14 14:58:45 -070048 return 0;
49 }
50
San Mehat7e8529a2010-03-25 09:31:42 -070051 SLOGD("Starting service '%s'", name);
San Mehatc41d1c82009-05-14 14:58:45 -070052 property_set("ctl.start", name);
53
David 'Digit' Turneraf174f02011-01-17 02:22:22 +010054 int count = SLEEP_MAX_USEC;
55 while(count > 0) {
56 usleep(SLEEP_MIN_USEC);
57 count -= SLEEP_MIN_USEC;
San Mehatc41d1c82009-05-14 14:58:45 -070058 if (isRunning(name))
59 break;
60 }
David 'Digit' Turneraf174f02011-01-17 02:22:22 +010061 if (count <= 0) {
San Mehat7e8529a2010-03-25 09:31:42 -070062 SLOGW("Timed out waiting for service '%s' to start", name);
San Mehatc41d1c82009-05-14 14:58:45 -070063 errno = ETIMEDOUT;
64 return -1;
65 }
San Mehat7e8529a2010-03-25 09:31:42 -070066 SLOGD("Sucessfully started '%s'", name);
San Mehatc41d1c82009-05-14 14:58:45 -070067 return 0;
68}
69
70int ServiceManager::stop(const char *name) {
David 'Digit' Turneraf174f02011-01-17 02:22:22 +010071 if (strlen(name) > SERVICE_NAME_MAX) {
72 SLOGE("Service name '%s' is too long", name);
73 return 0;
74 }
San Mehatc41d1c82009-05-14 14:58:45 -070075 if (!isRunning(name)) {
San Mehat7e8529a2010-03-25 09:31:42 -070076 SLOGW("Service '%s' is already stopped", name);
San Mehatc41d1c82009-05-14 14:58:45 -070077 return 0;
78 }
79
San Mehat7e8529a2010-03-25 09:31:42 -070080 SLOGD("Stopping service '%s'", name);
San Mehatc41d1c82009-05-14 14:58:45 -070081 property_set("ctl.stop", name);
82
David 'Digit' Turneraf174f02011-01-17 02:22:22 +010083 int count = SLEEP_MAX_USEC;
84 while(count > 0) {
85 usleep(SLEEP_MIN_USEC);
86 count -= SLEEP_MIN_USEC;
San Mehatc41d1c82009-05-14 14:58:45 -070087 if (!isRunning(name))
88 break;
89 }
90
David 'Digit' Turneraf174f02011-01-17 02:22:22 +010091 if (count <= 0) {
San Mehat7e8529a2010-03-25 09:31:42 -070092 SLOGW("Timed out waiting for service '%s' to stop", name);
San Mehatc41d1c82009-05-14 14:58:45 -070093 errno = ETIMEDOUT;
94 return -1;
95 }
David 'Digit' Turneraf174f02011-01-17 02:22:22 +010096 SLOGD("Successfully stopped '%s'", name);
San Mehatc41d1c82009-05-14 14:58:45 -070097 return 0;
98}
99
100bool ServiceManager::isRunning(const char *name) {
101 char propVal[PROPERTY_VALUE_MAX];
David 'Digit' Turneraf174f02011-01-17 02:22:22 +0100102 char propName[PROPERTY_KEY_MAX];
103 int ret;
San Mehatc41d1c82009-05-14 14:58:45 -0700104
David 'Digit' Turneraf174f02011-01-17 02:22:22 +0100105 ret = snprintf(propName, sizeof(propName), "init.svc.%s", name);
106 if (ret > (int)sizeof(propName)-1) {
107 SLOGD("Service name '%s' is too long", name);
108 return false;
109 }
San Mehatc41d1c82009-05-14 14:58:45 -0700110
111 if (property_get(propName, propVal, NULL)) {
112 if (!strcmp(propVal, "running"))
113 return true;
114 }
115 return false;
116}