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