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