Home | History | Annotate | Download | only in server
      1 /*
      2  * Copyright (C) 2013 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 com.android.server;
     18 
     19 import android.content.Context;
     20 import android.util.Slog;
     21 
     22 import java.lang.reflect.Constructor;
     23 import java.lang.reflect.InvocationTargetException;
     24 import java.util.ArrayList;
     25 
     26 /**
     27  * Manages creating, starting, and other lifecycle events of
     28  * {@link com.android.server.SystemService system services}.
     29  *
     30  * {@hide}
     31  */
     32 public class SystemServiceManager {
     33     private static final String TAG = "SystemServiceManager";
     34 
     35     private final Context mContext;
     36     private boolean mSafeMode;
     37 
     38     // Services that should receive lifecycle events.
     39     private final ArrayList<SystemService> mServices = new ArrayList<SystemService>();
     40 
     41     private int mCurrentPhase = -1;
     42 
     43     public SystemServiceManager(Context context) {
     44         mContext = context;
     45     }
     46 
     47     /**
     48      * Starts a service by class name.
     49      *
     50      * @return The service instance.
     51      */
     52     @SuppressWarnings("unchecked")
     53     public SystemService startService(String className) {
     54         final Class<SystemService> serviceClass;
     55         try {
     56             serviceClass = (Class<SystemService>)Class.forName(className);
     57         } catch (ClassNotFoundException ex) {
     58             Slog.i(TAG, "Starting " + className);
     59             throw new RuntimeException("Failed to create service " + className
     60                     + ": service class not found, usually indicates that the caller should "
     61                     + "have called PackageManager.hasSystemFeature() to check whether the "
     62                     + "feature is available on this device before trying to start the "
     63                     + "services that implement it", ex);
     64         }
     65         return startService(serviceClass);
     66     }
     67 
     68     /**
     69      * Creates and starts a system service. The class must be a subclass of
     70      * {@link com.android.server.SystemService}.
     71      *
     72      * @param serviceClass A Java class that implements the SystemService interface.
     73      * @return The service instance, never null.
     74      * @throws RuntimeException if the service fails to start.
     75      */
     76     @SuppressWarnings("unchecked")
     77     public <T extends SystemService> T startService(Class<T> serviceClass) {
     78         final String name = serviceClass.getName();
     79         Slog.i(TAG, "Starting " + name);
     80 
     81         // Create the service.
     82         if (!SystemService.class.isAssignableFrom(serviceClass)) {
     83             throw new RuntimeException("Failed to create " + name
     84                     + ": service must extend " + SystemService.class.getName());
     85         }
     86         final T service;
     87         try {
     88             Constructor<T> constructor = serviceClass.getConstructor(Context.class);
     89             service = constructor.newInstance(mContext);
     90         } catch (InstantiationException ex) {
     91             throw new RuntimeException("Failed to create service " + name
     92                     + ": service could not be instantiated", ex);
     93         } catch (IllegalAccessException ex) {
     94             throw new RuntimeException("Failed to create service " + name
     95                     + ": service must have a public constructor with a Context argument", ex);
     96         } catch (NoSuchMethodException ex) {
     97             throw new RuntimeException("Failed to create service " + name
     98                     + ": service must have a public constructor with a Context argument", ex);
     99         } catch (InvocationTargetException ex) {
    100             throw new RuntimeException("Failed to create service " + name
    101                     + ": service constructor threw an exception", ex);
    102         }
    103 
    104         // Register it.
    105         mServices.add(service);
    106 
    107         // Start it.
    108         try {
    109             service.onStart();
    110         } catch (RuntimeException ex) {
    111             throw new RuntimeException("Failed to start service " + name
    112                     + ": onStart threw an exception", ex);
    113         }
    114         return service;
    115     }
    116 
    117     /**
    118      * Starts the specified boot phase for all system services that have been started up to
    119      * this point.
    120      *
    121      * @param phase The boot phase to start.
    122      */
    123     public void startBootPhase(final int phase) {
    124         if (phase <= mCurrentPhase) {
    125             throw new IllegalArgumentException("Next phase must be larger than previous");
    126         }
    127         mCurrentPhase = phase;
    128 
    129         Slog.i(TAG, "Starting phase " + mCurrentPhase);
    130 
    131         final int serviceLen = mServices.size();
    132         for (int i = 0; i < serviceLen; i++) {
    133             final SystemService service = mServices.get(i);
    134             try {
    135                 service.onBootPhase(mCurrentPhase);
    136             } catch (Exception ex) {
    137                 throw new RuntimeException("Failed to boot service "
    138                         + service.getClass().getName()
    139                         + ": onBootPhase threw an exception during phase "
    140                         + mCurrentPhase, ex);
    141             }
    142         }
    143     }
    144 
    145     public void startUser(final int userHandle) {
    146         final int serviceLen = mServices.size();
    147         for (int i = 0; i < serviceLen; i++) {
    148             final SystemService service = mServices.get(i);
    149             try {
    150                 service.onStartUser(userHandle);
    151             } catch (Exception ex) {
    152                 Slog.wtf(TAG, "Failure reporting start of user " + userHandle
    153                         + " to service " + service.getClass().getName(), ex);
    154             }
    155         }
    156     }
    157 
    158     public void switchUser(final int userHandle) {
    159         final int serviceLen = mServices.size();
    160         for (int i = 0; i < serviceLen; i++) {
    161             final SystemService service = mServices.get(i);
    162             try {
    163                 service.onSwitchUser(userHandle);
    164             } catch (Exception ex) {
    165                 Slog.wtf(TAG, "Failure reporting switch of user " + userHandle
    166                         + " to service " + service.getClass().getName(), ex);
    167             }
    168         }
    169     }
    170 
    171     public void stopUser(final int userHandle) {
    172         final int serviceLen = mServices.size();
    173         for (int i = 0; i < serviceLen; i++) {
    174             final SystemService service = mServices.get(i);
    175             try {
    176                 service.onStopUser(userHandle);
    177             } catch (Exception ex) {
    178                 Slog.wtf(TAG, "Failure reporting stop of user " + userHandle
    179                         + " to service " + service.getClass().getName(), ex);
    180             }
    181         }
    182     }
    183 
    184     public void cleanupUser(final int userHandle) {
    185         final int serviceLen = mServices.size();
    186         for (int i = 0; i < serviceLen; i++) {
    187             final SystemService service = mServices.get(i);
    188             try {
    189                 service.onCleanupUser(userHandle);
    190             } catch (Exception ex) {
    191                 Slog.wtf(TAG, "Failure reporting cleanup of user " + userHandle
    192                         + " to service " + service.getClass().getName(), ex);
    193             }
    194         }
    195     }
    196 
    197     /** Sets the safe mode flag for services to query. */
    198     public void setSafeMode(boolean safeMode) {
    199         mSafeMode = safeMode;
    200     }
    201 
    202     /**
    203      * Returns whether we are booting into safe mode.
    204      * @return safe mode flag
    205      */
    206     public boolean isSafeMode() {
    207         return mSafeMode;
    208     }
    209 
    210     /**
    211      * Outputs the state of this manager to the System log.
    212      */
    213     public void dump() {
    214         StringBuilder builder = new StringBuilder();
    215         builder.append("Current phase: ").append(mCurrentPhase).append("\n");
    216         builder.append("Services:\n");
    217         final int startedLen = mServices.size();
    218         for (int i = 0; i < startedLen; i++) {
    219             final SystemService service = mServices.get(i);
    220             builder.append("\t")
    221                     .append(service.getClass().getSimpleName())
    222                     .append("\n");
    223         }
    224 
    225         Slog.e(TAG, builder.toString());
    226     }
    227 }
    228