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