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