19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.os;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkeyimport com.google.android.collect.Maps;
20088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
21088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkeyimport java.util.HashMap;
22088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkeyimport java.util.concurrent.TimeoutException;
23088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
24088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey/**
25088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey * Controls and utilities for low-level {@code init} services.
26088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey *
27088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey * @hide
28088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey */
29088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkeypublic class SystemService {
30088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
31088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    private static HashMap<String, State> sStates = Maps.newHashMap();
32088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
33088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    /**
34088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey     * State of a known {@code init} service.
35088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey     */
36088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    public enum State {
37088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        RUNNING("running"),
38088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        STOPPING("stopping"),
39088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        STOPPED("stopped"),
40088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        RESTARTING("restarting");
41088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
42088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        State(String state) {
43088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey            sStates.put(state, this);
44088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        }
45088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    }
46088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
47088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    private static Object sPropertyLock = new Object();
48088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
49088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    static {
50088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        SystemProperties.addChangeCallback(new Runnable() {
51088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey            @Override
52088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey            public void run() {
53088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                synchronized (sPropertyLock) {
54088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                    sPropertyLock.notifyAll();
55088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                }
56088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey            }
57088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        });
58088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    }
59088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
60088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    /** Request that the init daemon start a named service. */
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void start(String name) {
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SystemProperties.set("ctl.start", name);
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
64088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
65088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    /** Request that the init daemon stop a named service. */
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void stop(String name) {
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SystemProperties.set("ctl.stop", name);
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6930d4d57e8ed421a7d910c86c96c5648c899c2c9bWink Saville
7030d4d57e8ed421a7d910c86c96c5648c899c2c9bWink Saville    /** Request that the init daemon restart a named service. */
7130d4d57e8ed421a7d910c86c96c5648c899c2c9bWink Saville    public static void restart(String name) {
7230d4d57e8ed421a7d910c86c96c5648c899c2c9bWink Saville        SystemProperties.set("ctl.restart", name);
7330d4d57e8ed421a7d910c86c96c5648c899c2c9bWink Saville    }
74088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
75088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    /**
76088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey     * Return current state of given service.
77088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey     */
78088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    public static State getState(String service) {
79088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        final String rawState = SystemProperties.get("init.svc." + service);
80088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        final State state = sStates.get(rawState);
81088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        if (state != null) {
82088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey            return state;
83088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        } else {
84899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey            return State.STOPPED;
85088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        }
86088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    }
87088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
88088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    /**
89088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey     * Check if given service is {@link State#STOPPED}.
90088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey     */
91088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    public static boolean isStopped(String service) {
92088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        return State.STOPPED.equals(getState(service));
93088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    }
94088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
95088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    /**
96088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey     * Check if given service is {@link State#RUNNING}.
97088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey     */
98088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    public static boolean isRunning(String service) {
99088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        return State.RUNNING.equals(getState(service));
100088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    }
101088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
102088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    /**
103088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey     * Wait until given service has entered specific state.
104088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey     */
105088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    public static void waitForState(String service, State state, long timeoutMillis)
106088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey            throws TimeoutException {
107088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        final long endMillis = SystemClock.elapsedRealtime() + timeoutMillis;
108088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        while (true) {
109088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey            synchronized (sPropertyLock) {
110088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                final State currentState = getState(service);
111088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                if (state.equals(currentState)) {
112088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                    return;
113088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                }
114088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
115088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                if (SystemClock.elapsedRealtime() >= endMillis) {
116088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                    throw new TimeoutException("Service " + service + " currently " + currentState
117088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                            + "; waited " + timeoutMillis + "ms for " + state);
118088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                }
119088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
120088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                try {
121088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                    sPropertyLock.wait(timeoutMillis);
122088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                } catch (InterruptedException e) {
123088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                }
124088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey            }
125088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        }
126088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    }
127088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
128088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    /**
129088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey     * Wait until any of given services enters {@link State#STOPPED}.
130088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey     */
131088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    public static void waitForAnyStopped(String... services)  {
132088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        while (true) {
133088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey            synchronized (sPropertyLock) {
134088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                for (String service : services) {
135088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                    if (State.STOPPED.equals(getState(service))) {
136088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                        return;
137088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                    }
138088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                }
139088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
140088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                try {
141088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                    sPropertyLock.wait();
142088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                } catch (InterruptedException e) {
143088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                }
144088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey            }
145088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        }
146088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    }
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
148