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 getIServiceManager()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 getService(String name)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 */ getServiceOrThrow(String name)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 addService(String name, IBinder service)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 addService(String name, IBinder service, boolean allowIsolated)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 addService(String name, IBinder service, boolean allowIsolated, int dumpPriority)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 checkService(String name)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 listServices()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 */ initServiceCache(Map<String, IBinder> cache)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 { ServiceNotFoundException(String name)255 public ServiceNotFoundException(String name) { 256 super("No service published for: " + name); 257 } 258 } 259 rawGetService(String name)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