Home | History | Annotate | Download | only in src
      1 #include <errno.h>
      2 #include <string.h>
      3 
      4 #include <sysutils/ServiceManager.h>
      5 
      6 #define LOG_TAG "Service"
      7 #include <cutils/log.h>
      8 #include <cutils/properties.h>
      9 
     10 ServiceManager::ServiceManager() {
     11 }
     12 
     13 /* 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 
     41 int ServiceManager::start(const char *name) {
     42     if (strlen(name) > SERVICE_NAME_MAX) {
     43         SLOGE("Service name '%s' is too long", name);
     44         return 0;
     45     }
     46     if (isRunning(name)) {
     47         SLOGW("Service '%s' is already running", name);
     48         return 0;
     49     }
     50 
     51     SLOGD("Starting service '%s'", name);
     52     property_set("ctl.start", name);
     53 
     54     int count = SLEEP_MAX_USEC;
     55     while(count > 0) {
     56         usleep(SLEEP_MIN_USEC);
     57         count -= SLEEP_MIN_USEC;
     58         if (isRunning(name))
     59             break;
     60     }
     61     if (count <= 0) {
     62         SLOGW("Timed out waiting for service '%s' to start", name);
     63         errno = ETIMEDOUT;
     64         return -1;
     65     }
     66     SLOGD("Sucessfully started '%s'", name);
     67     return 0;
     68 }
     69 
     70 int ServiceManager::stop(const char *name) {
     71     if (strlen(name) > SERVICE_NAME_MAX) {
     72         SLOGE("Service name '%s' is too long", name);
     73         return 0;
     74     }
     75     if (!isRunning(name)) {
     76         SLOGW("Service '%s' is already stopped", name);
     77         return 0;
     78     }
     79 
     80     SLOGD("Stopping service '%s'", name);
     81     property_set("ctl.stop", name);
     82 
     83     int count = SLEEP_MAX_USEC;
     84     while(count > 0) {
     85         usleep(SLEEP_MIN_USEC);
     86         count -= SLEEP_MIN_USEC;
     87         if (!isRunning(name))
     88             break;
     89     }
     90 
     91     if (count <= 0) {
     92         SLOGW("Timed out waiting for service '%s' to stop", name);
     93         errno = ETIMEDOUT;
     94         return -1;
     95     }
     96     SLOGD("Successfully stopped '%s'", name);
     97     return 0;
     98 }
     99 
    100 bool ServiceManager::isRunning(const char *name) {
    101     char propVal[PROPERTY_VALUE_MAX];
    102     char propName[PROPERTY_KEY_MAX];
    103     int  ret;
    104 
    105     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     }
    110 
    111     if (property_get(propName, propVal, NULL)) {
    112         if (!strcmp(propVal, "running"))
    113             return true;
    114     }
    115     return false;
    116 }
    117