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