1 /* 2 * Copyright (C) 2006 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 package android.os; 18 19 import com.google.android.collect.Maps; 20 21 import android.annotation.UnsupportedAppUsage; 22 import java.util.HashMap; 23 import java.util.concurrent.TimeoutException; 24 25 /** 26 * Controls and utilities for low-level {@code init} services. 27 * 28 * @hide 29 */ 30 public class SystemService { 31 32 private static HashMap<String, State> sStates = Maps.newHashMap(); 33 34 /** 35 * State of a known {@code init} service. 36 */ 37 public enum State { 38 RUNNING("running"), 39 STOPPING("stopping"), 40 STOPPED("stopped"), 41 RESTARTING("restarting"); 42 43 State(String state) { 44 sStates.put(state, this); 45 } 46 } 47 48 private static Object sPropertyLock = new Object(); 49 50 static { 51 SystemProperties.addChangeCallback(new Runnable() { 52 @Override 53 public void run() { 54 synchronized (sPropertyLock) { 55 sPropertyLock.notifyAll(); 56 } 57 } 58 }); 59 } 60 61 /** Request that the init daemon start a named service. */ 62 @UnsupportedAppUsage 63 public static void start(String name) { 64 SystemProperties.set("ctl.start", name); 65 } 66 67 /** Request that the init daemon stop a named service. */ 68 @UnsupportedAppUsage 69 public static void stop(String name) { 70 SystemProperties.set("ctl.stop", name); 71 } 72 73 /** Request that the init daemon restart a named service. */ 74 public static void restart(String name) { 75 SystemProperties.set("ctl.restart", name); 76 } 77 78 /** 79 * Return current state of given service. 80 */ 81 public static State getState(String service) { 82 final String rawState = SystemProperties.get("init.svc." + service); 83 final State state = sStates.get(rawState); 84 if (state != null) { 85 return state; 86 } else { 87 return State.STOPPED; 88 } 89 } 90 91 /** 92 * Check if given service is {@link State#STOPPED}. 93 */ 94 public static boolean isStopped(String service) { 95 return State.STOPPED.equals(getState(service)); 96 } 97 98 /** 99 * Check if given service is {@link State#RUNNING}. 100 */ 101 public static boolean isRunning(String service) { 102 return State.RUNNING.equals(getState(service)); 103 } 104 105 /** 106 * Wait until given service has entered specific state. 107 */ 108 public static void waitForState(String service, State state, long timeoutMillis) 109 throws TimeoutException { 110 final long endMillis = SystemClock.elapsedRealtime() + timeoutMillis; 111 while (true) { 112 synchronized (sPropertyLock) { 113 final State currentState = getState(service); 114 if (state.equals(currentState)) { 115 return; 116 } 117 118 if (SystemClock.elapsedRealtime() >= endMillis) { 119 throw new TimeoutException("Service " + service + " currently " + currentState 120 + "; waited " + timeoutMillis + "ms for " + state); 121 } 122 123 try { 124 sPropertyLock.wait(timeoutMillis); 125 } catch (InterruptedException e) { 126 } 127 } 128 } 129 } 130 131 /** 132 * Wait until any of given services enters {@link State#STOPPED}. 133 */ 134 public static void waitForAnyStopped(String... services) { 135 while (true) { 136 synchronized (sPropertyLock) { 137 for (String service : services) { 138 if (State.STOPPED.equals(getState(service))) { 139 return; 140 } 141 } 142 143 try { 144 sPropertyLock.wait(); 145 } catch (InterruptedException e) { 146 } 147 } 148 } 149 } 150 } 151