1c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat#include <errno.h>
2b93e5812faffd3b6c5fb349072413aace31918d8Olivier Bailly#include <string.h>
3c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat
4c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat#include <sysutils/ServiceManager.h>
5c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat
6c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat#define LOG_TAG "Service"
7c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat#include <cutils/log.h>
8c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat#include <cutils/properties.h>
9c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat
10c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan MehatServiceManager::ServiceManager() {
11c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat}
12c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat
13af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner/* The service name should not exceed SERVICE_NAME_MAX to avoid
14af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner * some weird things. This is due to the fact that:
15af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner *
16af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner * - Starting a service is done by writing its name to the "ctl.start"
17af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner *   system property. This triggers the init daemon to actually start
18af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner *   the service for us.
19af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner *
20af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner * - Stopping the service is done by writing its name to "ctl.stop"
21af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner *   in a similar way.
22af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner *
23af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner * - Reading the status of a service is done by reading the property
24af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner *   named "init.svc.<name>"
25af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner *
26af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner * If strlen(<name>) > (PROPERTY_KEY_MAX-1)-9, then you can start/stop
27af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner * the service by writing to ctl.start/stop, but you won't be able to
28af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner * read its state due to the truncation of "init.svc.<name>" into a
29af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner * zero-terminated buffer of PROPERTY_KEY_MAX characters.
30af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner */
31af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner#define SERVICE_NAME_MAX  (PROPERTY_KEY_MAX-10)
32af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner
33af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner/* The maximum amount of time to wait for a service to start or stop,
34af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner * in micro-seconds (really an approximation) */
35af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner#define  SLEEP_MAX_USEC     2000000  /* 2 seconds */
36af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner
37af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner/* The minimal sleeping interval between checking for the service's state
38af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner * when looping for SLEEP_MAX_USEC */
39af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner#define  SLEEP_MIN_USEC      200000  /* 200 msec */
40af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner
41c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehatint ServiceManager::start(const char *name) {
42af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner    if (strlen(name) > SERVICE_NAME_MAX) {
43af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner        SLOGE("Service name '%s' is too long", name);
44af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner        return 0;
45af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner    }
46c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat    if (isRunning(name)) {
477e8529a8b528fd30586aa037f15a31b29582c537San Mehat        SLOGW("Service '%s' is already running", name);
48c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat        return 0;
49c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat    }
50c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat
517e8529a8b528fd30586aa037f15a31b29582c537San Mehat    SLOGD("Starting service '%s'", name);
52c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat    property_set("ctl.start", name);
53c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat
54af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner    int count = SLEEP_MAX_USEC;
55af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner    while(count > 0) {
56af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner        usleep(SLEEP_MIN_USEC);
57af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner        count -= SLEEP_MIN_USEC;
58c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat        if (isRunning(name))
59c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat            break;
60c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat    }
61af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner    if (count <= 0) {
627e8529a8b528fd30586aa037f15a31b29582c537San Mehat        SLOGW("Timed out waiting for service '%s' to start", name);
63c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat        errno = ETIMEDOUT;
64c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat        return -1;
65c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat    }
667e8529a8b528fd30586aa037f15a31b29582c537San Mehat    SLOGD("Sucessfully started '%s'", name);
67c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat    return 0;
68c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat}
69c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat
70c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehatint ServiceManager::stop(const char *name) {
71af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner    if (strlen(name) > SERVICE_NAME_MAX) {
72af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner        SLOGE("Service name '%s' is too long", name);
73af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner        return 0;
74af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner    }
75c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat    if (!isRunning(name)) {
767e8529a8b528fd30586aa037f15a31b29582c537San Mehat        SLOGW("Service '%s' is already stopped", name);
77c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat        return 0;
78c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat    }
79c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat
807e8529a8b528fd30586aa037f15a31b29582c537San Mehat    SLOGD("Stopping service '%s'", name);
81c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat    property_set("ctl.stop", name);
82c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat
83af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner    int count = SLEEP_MAX_USEC;
84af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner    while(count > 0) {
85af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner        usleep(SLEEP_MIN_USEC);
86af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner        count -= SLEEP_MIN_USEC;
87c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat        if (!isRunning(name))
88c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat            break;
89c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat    }
90c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat
91af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner    if (count <= 0) {
927e8529a8b528fd30586aa037f15a31b29582c537San Mehat        SLOGW("Timed out waiting for service '%s' to stop", name);
93c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat        errno = ETIMEDOUT;
94c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat        return -1;
95c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat    }
96af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner    SLOGD("Successfully stopped '%s'", name);
97c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat    return 0;
98c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat}
99c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat
100c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehatbool ServiceManager::isRunning(const char *name) {
101c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat    char propVal[PROPERTY_VALUE_MAX];
102af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner    char propName[PROPERTY_KEY_MAX];
103af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner    int  ret;
104c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat
105af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner    ret = snprintf(propName, sizeof(propName), "init.svc.%s", name);
106af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner    if (ret > (int)sizeof(propName)-1) {
107af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner        SLOGD("Service name '%s' is too long", name);
108af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner        return false;
109af174f0039bf462c36b89fd1439a44c60c4b89c9David 'Digit' Turner    }
110c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat
111c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat    if (property_get(propName, propVal, NULL)) {
112c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat        if (!strcmp(propVal, "running"))
113c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat            return true;
114c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat    }
115c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat    return false;
116c41d1c8074ed02acc9d1e749d81e0aafb5efbbfaSan Mehat}
117