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