content: /*
   * Copyright (C) 2006 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package android.os;
  
  import com.google.android.collect.Maps;
  
  import android.annotation.UnsupportedAppUsage;
  import java.util.HashMap;
  import java.util.concurrent.TimeoutException;
  
  /**
   * Controls and utilities for low-level {@code init} services.
   *
   * @hide
   */
  public class SystemService {
  
      private static HashMap<String, State> sStates = Maps.newHashMap();
  
      /**
       * State of a known {@code init} service.
       */
      public enum State {
          RUNNING("running"),
          STOPPING("stopping"),
          STOPPED("stopped"),
          RESTARTING("restarting");
  
          State(String state) {
              sStates.put(state, this);
          }
      }
  
      private static Object sPropertyLock = new Object();
  
      static {
          SystemProperties.addChangeCallback(new Runnable() {
              @Override
              public void run() {
                  synchronized (sPropertyLock) {
                      sPropertyLock.notifyAll();
                  }
              }
          });
      }
  
      /** Request that the init daemon start a named service. */
      @UnsupportedAppUsage
      public static void start(String name) {
          SystemProperties.set("ctl.start", name);
      }
  
      /** Request that the init daemon stop a named service. */
      @UnsupportedAppUsage
      public static void stop(String name) {
          SystemProperties.set("ctl.stop", name);
      }
  
      /** Request that the init daemon restart a named service. */
      public static void restart(String name) {
          SystemProperties.set("ctl.restart", name);
      }
  
      /**
       * Return current state of given service.
       */
      public static State getState(String service) {
          final String rawState = SystemProperties.get("init.svc." + service);
          final State state = sStates.get(rawState);
          if (state != null) {
              return state;
          } else {
              return State.STOPPED;
          }
      }
  
      /**
       * Check if given service is {@link State#STOPPED}.
       */
      public static boolean isStopped(String service) {
          return State.STOPPED.equals(getState(service));
      }
  
      /**
       * Check if given service is {@link State#RUNNING}.
       */
      public static boolean isRunning(String service) {
          return State.RUNNING.equals(getState(service));
      }
  
      /**
       * Wait until given service has entered specific state.
       */
      public static void waitForState(String service, State state, long timeoutMillis)
              throws TimeoutException {
          final long endMillis = SystemClock.elapsedRealtime() + timeoutMillis;
          while (true) {
              synchronized (sPropertyLock) {
                  final State currentState = getState(service);
                  if (state.equals(currentState)) {
                      return;
                  }
  
                  if (SystemClock.elapsedRealtime() >= endMillis) {
                      throw new TimeoutException("Service " + service + " currently " + currentState
                              + "; waited " + timeoutMillis + "ms for " + state);
                  }
  
                  try {
                      sPropertyLock.wait(timeoutMillis);
                  } catch (InterruptedException e) {
                  }
              }
          }
      }
  
      /**
       * Wait until any of given services enters {@link State#STOPPED}.
       */
      public static void waitForAnyStopped(String... services)  {
          while (true) {
              synchronized (sPropertyLock) {
                  for (String service : services) {
                      if (State.STOPPED.equals(getState(service))) {
                          return;
                      }
                  }
  
                  try {
                      sPropertyLock.wait();
                  } catch (InterruptedException e) {
                  }
              }
          }
      }
  }
  