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