blob: 1abe988a884a7a5a465416ba790ec1d34af23dbb [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>
Olivier Baillyb93e5812010-11-17 11:47:23 -080020#include <string.h>
San Mehatc41d1c82009-05-14 14:58:45 -070021
Mark Salyzyn66ce3e02016-09-28 10:07:20 -070022#include <android/log.h>
San Mehatc41d1c82009-05-14 14:58:45 -070023#include <cutils/properties.h>
Mark Salyzyn66ce3e02016-09-28 10:07:20 -070024#include <sysutils/ServiceManager.h>
San Mehatc41d1c82009-05-14 14:58:45 -070025
26ServiceManager::ServiceManager() {
27}
28
David 'Digit' Turneraf174f02011-01-17 02:22:22 +010029/* The service name should not exceed SERVICE_NAME_MAX to avoid
30 * some weird things. This is due to the fact that:
31 *
32 * - Starting a service is done by writing its name to the "ctl.start"
33 * system property. This triggers the init daemon to actually start
34 * the service for us.
35 *
36 * - Stopping the service is done by writing its name to "ctl.stop"
37 * in a similar way.
38 *
39 * - Reading the status of a service is done by reading the property
40 * named "init.svc.<name>"
41 *
42 * If strlen(<name>) > (PROPERTY_KEY_MAX-1)-9, then you can start/stop
43 * the service by writing to ctl.start/stop, but you won't be able to
44 * read its state due to the truncation of "init.svc.<name>" into a
45 * zero-terminated buffer of PROPERTY_KEY_MAX characters.
46 */
47#define SERVICE_NAME_MAX (PROPERTY_KEY_MAX-10)
48
49/* The maximum amount of time to wait for a service to start or stop,
50 * in micro-seconds (really an approximation) */
51#define SLEEP_MAX_USEC 2000000 /* 2 seconds */
52
53/* The minimal sleeping interval between checking for the service's state
54 * when looping for SLEEP_MAX_USEC */
55#define SLEEP_MIN_USEC 200000 /* 200 msec */
56
San Mehatc41d1c82009-05-14 14:58:45 -070057int ServiceManager::start(const char *name) {
David 'Digit' Turneraf174f02011-01-17 02:22:22 +010058 if (strlen(name) > SERVICE_NAME_MAX) {
59 SLOGE("Service name '%s' is too long", name);
60 return 0;
61 }
San Mehatc41d1c82009-05-14 14:58:45 -070062 if (isRunning(name)) {
San Mehat7e8529a2010-03-25 09:31:42 -070063 SLOGW("Service '%s' is already running", name);
San Mehatc41d1c82009-05-14 14:58:45 -070064 return 0;
65 }
66
San Mehat7e8529a2010-03-25 09:31:42 -070067 SLOGD("Starting service '%s'", name);
San Mehatc41d1c82009-05-14 14:58:45 -070068 property_set("ctl.start", name);
69
David 'Digit' Turneraf174f02011-01-17 02:22:22 +010070 int count = SLEEP_MAX_USEC;
71 while(count > 0) {
72 usleep(SLEEP_MIN_USEC);
73 count -= SLEEP_MIN_USEC;
San Mehatc41d1c82009-05-14 14:58:45 -070074 if (isRunning(name))
75 break;
76 }
David 'Digit' Turneraf174f02011-01-17 02:22:22 +010077 if (count <= 0) {
San Mehat7e8529a2010-03-25 09:31:42 -070078 SLOGW("Timed out waiting for service '%s' to start", name);
San Mehatc41d1c82009-05-14 14:58:45 -070079 errno = ETIMEDOUT;
80 return -1;
81 }
San Mehat7e8529a2010-03-25 09:31:42 -070082 SLOGD("Sucessfully started '%s'", name);
San Mehatc41d1c82009-05-14 14:58:45 -070083 return 0;
84}
85
86int ServiceManager::stop(const char *name) {
David 'Digit' Turneraf174f02011-01-17 02:22:22 +010087 if (strlen(name) > SERVICE_NAME_MAX) {
88 SLOGE("Service name '%s' is too long", name);
89 return 0;
90 }
San Mehatc41d1c82009-05-14 14:58:45 -070091 if (!isRunning(name)) {
San Mehat7e8529a2010-03-25 09:31:42 -070092 SLOGW("Service '%s' is already stopped", name);
San Mehatc41d1c82009-05-14 14:58:45 -070093 return 0;
94 }
95
San Mehat7e8529a2010-03-25 09:31:42 -070096 SLOGD("Stopping service '%s'", name);
San Mehatc41d1c82009-05-14 14:58:45 -070097 property_set("ctl.stop", name);
98
David 'Digit' Turneraf174f02011-01-17 02:22:22 +010099 int count = SLEEP_MAX_USEC;
100 while(count > 0) {
101 usleep(SLEEP_MIN_USEC);
102 count -= SLEEP_MIN_USEC;
San Mehatc41d1c82009-05-14 14:58:45 -0700103 if (!isRunning(name))
104 break;
105 }
106
David 'Digit' Turneraf174f02011-01-17 02:22:22 +0100107 if (count <= 0) {
San Mehat7e8529a2010-03-25 09:31:42 -0700108 SLOGW("Timed out waiting for service '%s' to stop", name);
San Mehatc41d1c82009-05-14 14:58:45 -0700109 errno = ETIMEDOUT;
110 return -1;
111 }
David 'Digit' Turneraf174f02011-01-17 02:22:22 +0100112 SLOGD("Successfully stopped '%s'", name);
San Mehatc41d1c82009-05-14 14:58:45 -0700113 return 0;
114}
115
116bool ServiceManager::isRunning(const char *name) {
117 char propVal[PROPERTY_VALUE_MAX];
David 'Digit' Turneraf174f02011-01-17 02:22:22 +0100118 char propName[PROPERTY_KEY_MAX];
119 int ret;
San Mehatc41d1c82009-05-14 14:58:45 -0700120
David 'Digit' Turneraf174f02011-01-17 02:22:22 +0100121 ret = snprintf(propName, sizeof(propName), "init.svc.%s", name);
122 if (ret > (int)sizeof(propName)-1) {
123 SLOGD("Service name '%s' is too long", name);
124 return false;
125 }
San Mehatc41d1c82009-05-14 14:58:45 -0700126
127 if (property_get(propName, propVal, NULL)) {
128 if (!strcmp(propVal, "running"))
129 return true;
130 }
131 return false;
132}