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
19899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkeyimport android.util.Slog;
20899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey
21088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkeyimport com.google.android.collect.Maps;
22088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
23088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkeyimport java.util.HashMap;
24088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkeyimport java.util.concurrent.TimeoutException;
25088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
26088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey/**
27088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey * Controls and utilities for low-level {@code init} services.
28088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey *
29088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey * @hide
30088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey */
31088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkeypublic class SystemService {
32088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
33088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    private static HashMap<String, State> sStates = Maps.newHashMap();
34088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
35088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    /**
36088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey     * State of a known {@code init} service.
37088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey     */
38088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    public enum State {
39088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        RUNNING("running"),
40088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        STOPPING("stopping"),
41088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        STOPPED("stopped"),
42088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        RESTARTING("restarting");
43088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
44088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        State(String state) {
45088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey            sStates.put(state, this);
46088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        }
47088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    }
48088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
49088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    private static Object sPropertyLock = new Object();
50088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
51088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    static {
52088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        SystemProperties.addChangeCallback(new Runnable() {
53088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey            @Override
54088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey            public void run() {
55088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                synchronized (sPropertyLock) {
56088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                    sPropertyLock.notifyAll();
57088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                }
58088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey            }
59088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        });
60088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    }
61088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
62088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    /** Request that the init daemon start a named service. */
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void start(String name) {
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SystemProperties.set("ctl.start", name);
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
66088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
67088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    /** Request that the init daemon stop a named service. */
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void stop(String name) {
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SystemProperties.set("ctl.stop", name);
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7130d4d57e8ed421a7d910c86c96c5648c899c2c9bWink Saville
7230d4d57e8ed421a7d910c86c96c5648c899c2c9bWink Saville    /** Request that the init daemon restart a named service. */
7330d4d57e8ed421a7d910c86c96c5648c899c2c9bWink Saville    public static void restart(String name) {
7430d4d57e8ed421a7d910c86c96c5648c899c2c9bWink Saville        SystemProperties.set("ctl.restart", name);
7530d4d57e8ed421a7d910c86c96c5648c899c2c9bWink Saville    }
76088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
77088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    /**
78088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey     * Return current state of given service.
79088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey     */
80088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    public static State getState(String service) {
81088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        final String rawState = SystemProperties.get("init.svc." + service);
82088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        final State state = sStates.get(rawState);
83088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        if (state != null) {
84088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey            return state;
85088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        } else {
86899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey            return State.STOPPED;
87088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        }
88088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    }
89088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
90088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    /**
91088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey     * Check if given service is {@link State#STOPPED}.
92088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey     */
93088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    public static boolean isStopped(String service) {
94088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        return State.STOPPED.equals(getState(service));
95088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    }
96088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
97088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    /**
98088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey     * Check if given service is {@link State#RUNNING}.
99088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey     */
100088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    public static boolean isRunning(String service) {
101088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        return State.RUNNING.equals(getState(service));
102088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    }
103088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
104088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    /**
105088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey     * Wait until given service has entered specific state.
106088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey     */
107088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    public static void waitForState(String service, State state, long timeoutMillis)
108088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey            throws TimeoutException {
109088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        final long endMillis = SystemClock.elapsedRealtime() + timeoutMillis;
110088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        while (true) {
111088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey            synchronized (sPropertyLock) {
112088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                final State currentState = getState(service);
113088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                if (state.equals(currentState)) {
114088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                    return;
115088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                }
116088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
117088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                if (SystemClock.elapsedRealtime() >= endMillis) {
118088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                    throw new TimeoutException("Service " + service + " currently " + currentState
119088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                            + "; waited " + timeoutMillis + "ms for " + state);
120088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                }
121088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
122088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                try {
123088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                    sPropertyLock.wait(timeoutMillis);
124088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                } catch (InterruptedException e) {
125088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                }
126088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey            }
127088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        }
128088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    }
129088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
130088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    /**
131088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey     * Wait until any of given services enters {@link State#STOPPED}.
132088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey     */
133088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    public static void waitForAnyStopped(String... services)  {
134088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        while (true) {
135088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey            synchronized (sPropertyLock) {
136088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                for (String service : services) {
137088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                    if (State.STOPPED.equals(getState(service))) {
138088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                        return;
139088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                    }
140088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                }
141088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey
142088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                try {
143088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                    sPropertyLock.wait();
144088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                } catch (InterruptedException e) {
145088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey                }
146088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey            }
147088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey        }
148088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey    }
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
150