Home | History | Annotate | Download | only in os
      1 /*
      2  * Copyright (C) 2007 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 android.os;
     18 
     19 import android.annotation.UnsupportedAppUsage;
     20 import android.util.ArrayMap;
     21 import android.util.Log;
     22 
     23 import com.android.internal.annotations.GuardedBy;
     24 import com.android.internal.os.BinderInternal;
     25 import com.android.internal.util.StatLogger;
     26 
     27 import java.util.Map;
     28 
     29 /** @hide */
     30 public final class ServiceManager {
     31     private static final String TAG = "ServiceManager";
     32     private static final Object sLock = new Object();
     33 
     34     @UnsupportedAppUsage
     35     private static IServiceManager sServiceManager;
     36 
     37     /**
     38      * Cache for the "well known" services, such as WM and AM.
     39      */
     40     @UnsupportedAppUsage
     41     private static Map<String, IBinder> sCache = new ArrayMap<String, IBinder>();
     42 
     43     /**
     44      * We do the "slow log" at most once every this interval.
     45      */
     46     private static final int SLOW_LOG_INTERVAL_MS = 5000;
     47 
     48     /**
     49      * We do the "stats log" at most once every this interval.
     50      */
     51     private static final int STATS_LOG_INTERVAL_MS = 5000;
     52 
     53     /**
     54      * Threshold in uS for a "slow" call, used on core UIDs. We use a more relax value to
     55      * avoid logspam.
     56      */
     57     private static final long GET_SERVICE_SLOW_THRESHOLD_US_CORE =
     58             SystemProperties.getInt("debug.servicemanager.slow_call_core_ms", 10) * 1000;
     59 
     60     /**
     61      * Threshold in uS for a "slow" call, used on non-core UIDs. We use a more relax value to
     62      * avoid logspam.
     63      */
     64     private static final long GET_SERVICE_SLOW_THRESHOLD_US_NON_CORE =
     65             SystemProperties.getInt("debug.servicemanager.slow_call_ms", 50) * 1000;
     66 
     67     /**
     68      * We log stats logging ever this many getService() calls.
     69      */
     70     private static final int GET_SERVICE_LOG_EVERY_CALLS_CORE =
     71             SystemProperties.getInt("debug.servicemanager.log_calls_core", 100);
     72 
     73     /**
     74      * We log stats logging ever this many getService() calls.
     75      */
     76     private static final int GET_SERVICE_LOG_EVERY_CALLS_NON_CORE =
     77             SystemProperties.getInt("debug.servicemanager.log_calls", 200);
     78 
     79     @GuardedBy("sLock")
     80     private static int sGetServiceAccumulatedUs;
     81 
     82     @GuardedBy("sLock")
     83     private static int sGetServiceAccumulatedCallCount;
     84 
     85     @GuardedBy("sLock")
     86     private static long sLastStatsLogUptime;
     87 
     88     @GuardedBy("sLock")
     89     private static long sLastSlowLogUptime;
     90 
     91     @GuardedBy("sLock")
     92     private static long sLastSlowLogActualTime;
     93 
     94     interface Stats {
     95         int GET_SERVICE = 0;
     96 
     97         int COUNT = GET_SERVICE + 1;
     98     }
     99 
    100     public static final StatLogger sStatLogger = new StatLogger(new String[] {
    101             "getService()",
    102     });
    103 
    104     @UnsupportedAppUsage
    105     private static IServiceManager getIServiceManager() {
    106         if (sServiceManager != null) {
    107             return sServiceManager;
    108         }
    109 
    110         // Find the service manager
    111         sServiceManager = ServiceManagerNative
    112                 .asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
    113         return sServiceManager;
    114     }
    115 
    116     /**
    117      * Returns a reference to a service with the given name.
    118      *
    119      * @param name the name of the service to get
    120      * @return a reference to the service, or <code>null</code> if the service doesn't exist
    121      */
    122     @UnsupportedAppUsage
    123     public static IBinder getService(String name) {
    124         try {
    125             IBinder service = sCache.get(name);
    126             if (service != null) {
    127                 return service;
    128             } else {
    129                 return Binder.allowBlocking(rawGetService(name));
    130             }
    131         } catch (RemoteException e) {
    132             Log.e(TAG, "error in getService", e);
    133         }
    134         return null;
    135     }
    136 
    137     /**
    138      * Returns a reference to a service with the given name, or throws
    139      * {@link NullPointerException} if none is found.
    140      *
    141      * @hide
    142      */
    143     public static IBinder getServiceOrThrow(String name) throws ServiceNotFoundException {
    144         final IBinder binder = getService(name);
    145         if (binder != null) {
    146             return binder;
    147         } else {
    148             throw new ServiceNotFoundException(name);
    149         }
    150     }
    151 
    152     /**
    153      * Place a new @a service called @a name into the service
    154      * manager.
    155      *
    156      * @param name the name of the new service
    157      * @param service the service object
    158      */
    159     @UnsupportedAppUsage
    160     public static void addService(String name, IBinder service) {
    161         addService(name, service, false, IServiceManager.DUMP_FLAG_PRIORITY_DEFAULT);
    162     }
    163 
    164     /**
    165      * Place a new @a service called @a name into the service
    166      * manager.
    167      *
    168      * @param name the name of the new service
    169      * @param service the service object
    170      * @param allowIsolated set to true to allow isolated sandboxed processes
    171      * to access this service
    172      */
    173     @UnsupportedAppUsage
    174     public static void addService(String name, IBinder service, boolean allowIsolated) {
    175         addService(name, service, allowIsolated, IServiceManager.DUMP_FLAG_PRIORITY_DEFAULT);
    176     }
    177 
    178     /**
    179      * Place a new @a service called @a name into the service
    180      * manager.
    181      *
    182      * @param name the name of the new service
    183      * @param service the service object
    184      * @param allowIsolated set to true to allow isolated sandboxed processes
    185      * @param dumpPriority supported dump priority levels as a bitmask
    186      * to access this service
    187      */
    188     @UnsupportedAppUsage
    189     public static void addService(String name, IBinder service, boolean allowIsolated,
    190             int dumpPriority) {
    191         try {
    192             getIServiceManager().addService(name, service, allowIsolated, dumpPriority);
    193         } catch (RemoteException e) {
    194             Log.e(TAG, "error in addService", e);
    195         }
    196     }
    197 
    198     /**
    199      * Retrieve an existing service called @a name from the
    200      * service manager.  Non-blocking.
    201      */
    202     @UnsupportedAppUsage
    203     public static IBinder checkService(String name) {
    204         try {
    205             IBinder service = sCache.get(name);
    206             if (service != null) {
    207                 return service;
    208             } else {
    209                 return Binder.allowBlocking(getIServiceManager().checkService(name));
    210             }
    211         } catch (RemoteException e) {
    212             Log.e(TAG, "error in checkService", e);
    213             return null;
    214         }
    215     }
    216 
    217     /**
    218      * Return a list of all currently running services.
    219      * @return an array of all currently running services, or <code>null</code> in
    220      * case of an exception
    221      */
    222     @UnsupportedAppUsage
    223     public static String[] listServices() {
    224         try {
    225             return getIServiceManager().listServices(IServiceManager.DUMP_FLAG_PRIORITY_ALL);
    226         } catch (RemoteException e) {
    227             Log.e(TAG, "error in listServices", e);
    228             return null;
    229         }
    230     }
    231 
    232     /**
    233      * This is only intended to be called when the process is first being brought
    234      * up and bound by the activity manager. There is only one thread in the process
    235      * at that time, so no locking is done.
    236      *
    237      * @param cache the cache of service references
    238      * @hide
    239      */
    240     public static void initServiceCache(Map<String, IBinder> cache) {
    241         if (sCache.size() != 0) {
    242             throw new IllegalStateException("setServiceCache may only be called once");
    243         }
    244         sCache.putAll(cache);
    245     }
    246 
    247     /**
    248      * Exception thrown when no service published for given name. This might be
    249      * thrown early during boot before certain services have published
    250      * themselves.
    251      *
    252      * @hide
    253      */
    254     public static class ServiceNotFoundException extends Exception {
    255         public ServiceNotFoundException(String name) {
    256             super("No service published for: " + name);
    257         }
    258     }
    259 
    260     private static IBinder rawGetService(String name) throws RemoteException {
    261         final long start = sStatLogger.getTime();
    262 
    263         final IBinder binder = getIServiceManager().getService(name);
    264 
    265         final int time = (int) sStatLogger.logDurationStat(Stats.GET_SERVICE, start);
    266 
    267         final int myUid = Process.myUid();
    268         final boolean isCore = UserHandle.isCore(myUid);
    269 
    270         final long slowThreshold = isCore
    271                 ? GET_SERVICE_SLOW_THRESHOLD_US_CORE
    272                 : GET_SERVICE_SLOW_THRESHOLD_US_NON_CORE;
    273 
    274         synchronized (sLock) {
    275             sGetServiceAccumulatedUs += time;
    276             sGetServiceAccumulatedCallCount++;
    277 
    278             final long nowUptime = SystemClock.uptimeMillis();
    279 
    280             // Was a slow call?
    281             if (time >= slowThreshold) {
    282                 // We do a slow log:
    283                 // - At most once in every SLOW_LOG_INTERVAL_MS
    284                 // - OR it was slower than the previously logged slow call.
    285                 if ((nowUptime > (sLastSlowLogUptime + SLOW_LOG_INTERVAL_MS))
    286                         || (sLastSlowLogActualTime < time)) {
    287                     EventLogTags.writeServiceManagerSlow(time / 1000, name);
    288 
    289                     sLastSlowLogUptime = nowUptime;
    290                     sLastSlowLogActualTime = time;
    291                 }
    292             }
    293 
    294             // Every GET_SERVICE_LOG_EVERY_CALLS calls, log the total time spent in getService().
    295 
    296             final int logInterval = isCore
    297                     ? GET_SERVICE_LOG_EVERY_CALLS_CORE
    298                     : GET_SERVICE_LOG_EVERY_CALLS_NON_CORE;
    299 
    300             if ((sGetServiceAccumulatedCallCount >= logInterval)
    301                     && (nowUptime >= (sLastStatsLogUptime + STATS_LOG_INTERVAL_MS))) {
    302 
    303                 EventLogTags.writeServiceManagerStats(
    304                         sGetServiceAccumulatedCallCount, // Total # of getService() calls.
    305                         sGetServiceAccumulatedUs / 1000, // Total time spent in getService() calls.
    306                         (int) (nowUptime - sLastStatsLogUptime)); // Uptime duration since last log.
    307                 sGetServiceAccumulatedCallCount = 0;
    308                 sGetServiceAccumulatedUs = 0;
    309                 sLastStatsLogUptime = nowUptime;
    310             }
    311         }
    312         return binder;
    313     }
    314 }
    315