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