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.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.SystemApi; 22 import android.compat.annotation.UnsupportedAppUsage; 23 import android.util.ArrayMap; 24 import android.util.Log; 25 26 import com.android.internal.annotations.GuardedBy; 27 import com.android.internal.os.BinderInternal; 28 import com.android.internal.util.Preconditions; 29 import com.android.internal.util.StatLogger; 30 31 import java.util.Map; 32 33 /** 34 * Manage binder services as registered with the binder context manager. These services must be 35 * declared statically on an Android device (SELinux access_vector service_manager, w/ service 36 * names in service_contexts files), and they do not follow the activity lifecycle. When 37 * building applications, android.app.Service should be preferred. 38 * 39 * @hide 40 **/ 41 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) 42 @android.ravenwood.annotation.RavenwoodKeepPartialClass 43 public final class ServiceManager { 44 private static final String TAG = "ServiceManager"; 45 private static final Object sLock = new Object(); 46 47 @UnsupportedAppUsage 48 private static IServiceManager sServiceManager; 49 50 /** 51 * Cache for the "well known" services, such as WM and AM. 52 */ 53 // NOTE: this cache is designed to be populated exactly once at process 54 // start to avoid any overhead from locking 55 @UnsupportedAppUsage 56 private static Map<String, IBinder> sCache = new ArrayMap<String, IBinder>(); 57 58 @GuardedBy("ServiceManager.class") 59 // NOTE: this cache is designed to support mutation by tests, so we require 60 // a lock to be held for all accesses 61 private static Map<String, IBinder> sCache$ravenwood; 62 63 /** 64 * We do the "slow log" at most once every this interval. 65 */ 66 private static final int SLOW_LOG_INTERVAL_MS = 5000; 67 68 /** 69 * We do the "stats log" at most once every this interval. 70 */ 71 private static final int STATS_LOG_INTERVAL_MS = 5000; 72 73 /** 74 * Threshold in uS for a "slow" call, used on core UIDs. We use a more relax value to 75 * avoid logspam. 76 */ 77 private static final long GET_SERVICE_SLOW_THRESHOLD_US_CORE = 78 SystemProperties.getInt("debug.servicemanager.slow_call_core_ms", 10) * 1000; 79 80 /** 81 * Threshold in uS for a "slow" call, used on non-core UIDs. We use a more relax value to 82 * avoid logspam. 83 */ 84 private static final long GET_SERVICE_SLOW_THRESHOLD_US_NON_CORE = 85 SystemProperties.getInt("debug.servicemanager.slow_call_ms", 50) * 1000; 86 87 /** 88 * We log stats logging ever this many getService() calls. 89 */ 90 private static final int GET_SERVICE_LOG_EVERY_CALLS_CORE = 91 SystemProperties.getInt("debug.servicemanager.log_calls_core", 100); 92 93 /** 94 * We log stats logging ever this many getService() calls. 95 */ 96 private static final int GET_SERVICE_LOG_EVERY_CALLS_NON_CORE = 97 SystemProperties.getInt("debug.servicemanager.log_calls", 200); 98 99 @GuardedBy("sLock") 100 private static int sGetServiceAccumulatedUs; 101 102 @GuardedBy("sLock") 103 private static int sGetServiceAccumulatedCallCount; 104 105 @GuardedBy("sLock") 106 private static long sLastStatsLogUptime; 107 108 @GuardedBy("sLock") 109 private static long sLastSlowLogUptime; 110 111 @GuardedBy("sLock") 112 private static long sLastSlowLogActualTime; 113 114 interface Stats { 115 int GET_SERVICE = 0; 116 117 int COUNT = GET_SERVICE + 1; 118 } 119 120 /** @hide */ 121 public static final StatLogger sStatLogger = new StatLogger(new String[] { 122 "getService()", 123 }); 124 125 /** @hide */ 126 @UnsupportedAppUsage 127 @android.ravenwood.annotation.RavenwoodKeep ServiceManager()128 public ServiceManager() { 129 } 130 131 /** @hide */ 132 @android.ravenwood.annotation.RavenwoodKeep init$ravenwood()133 public static void init$ravenwood() { 134 synchronized (ServiceManager.class) { 135 sCache$ravenwood = new ArrayMap<>(); 136 } 137 } 138 139 /** @hide */ 140 @android.ravenwood.annotation.RavenwoodKeep reset$ravenwood()141 public static void reset$ravenwood() { 142 synchronized (ServiceManager.class) { 143 sCache$ravenwood.clear(); 144 sCache$ravenwood = null; 145 } 146 } 147 148 @UnsupportedAppUsage getIServiceManager()149 private static IServiceManager getIServiceManager() { 150 if (sServiceManager != null) { 151 return sServiceManager; 152 } 153 154 // Find the service manager 155 sServiceManager = ServiceManagerNative 156 .asInterface(Binder.allowBlocking(BinderInternal.getContextObject())); 157 return sServiceManager; 158 } 159 160 /** 161 * Returns a reference to a service with the given name. 162 * 163 * @param name the name of the service to get 164 * @return a reference to the service, or <code>null</code> if the service doesn't exist 165 * @hide 166 */ 167 @UnsupportedAppUsage 168 @android.ravenwood.annotation.RavenwoodReplace getService(String name)169 public static IBinder getService(String name) { 170 try { 171 IBinder service = sCache.get(name); 172 if (service != null) { 173 return service; 174 } else { 175 return Binder.allowBlocking(rawGetService(name)); 176 } 177 } catch (RemoteException e) { 178 Log.e(TAG, "error in getService", e); 179 } 180 return null; 181 } 182 183 /** @hide */ getService$ravenwood(String name)184 public static IBinder getService$ravenwood(String name) { 185 synchronized (ServiceManager.class) { 186 // Ravenwood is a single-process environment, so it only needs to store locally 187 return Preconditions.requireNonNullViaRavenwoodRule(sCache$ravenwood).get(name); 188 } 189 } 190 191 /** 192 * Returns a reference to a service with the given name, or throws 193 * {@link ServiceNotFoundException} if none is found. 194 * 195 * @hide 196 */ 197 @android.ravenwood.annotation.RavenwoodKeep getServiceOrThrow(String name)198 public static IBinder getServiceOrThrow(String name) throws ServiceNotFoundException { 199 final IBinder binder = getService(name); 200 if (binder != null) { 201 return binder; 202 } else { 203 throw new ServiceNotFoundException(name); 204 } 205 } 206 207 /** 208 * Place a new @a service called @a name into the service 209 * manager. 210 * 211 * @param name the name of the new service 212 * @param service the service object 213 * @hide 214 */ 215 @UnsupportedAppUsage 216 @android.ravenwood.annotation.RavenwoodKeep addService(String name, IBinder service)217 public static void addService(String name, IBinder service) { 218 addService(name, service, false, IServiceManager.DUMP_FLAG_PRIORITY_DEFAULT); 219 } 220 221 /** 222 * Place a new @a service called @a name into the service 223 * manager. 224 * 225 * @param name the name of the new service 226 * @param service the service object 227 * @param allowIsolated set to true to allow isolated sandboxed processes 228 * to access this service 229 * @hide 230 */ 231 @UnsupportedAppUsage 232 @android.ravenwood.annotation.RavenwoodKeep addService(String name, IBinder service, boolean allowIsolated)233 public static void addService(String name, IBinder service, boolean allowIsolated) { 234 addService(name, service, allowIsolated, IServiceManager.DUMP_FLAG_PRIORITY_DEFAULT); 235 } 236 237 /** 238 * Place a new @a service called @a name into the service 239 * manager. 240 * 241 * @param name the name of the new service 242 * @param service the service object 243 * @param allowIsolated set to true to allow isolated sandboxed processes 244 * @param dumpPriority supported dump priority levels as a bitmask 245 * to access this service 246 * @hide 247 */ 248 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 249 @android.ravenwood.annotation.RavenwoodReplace addService(String name, IBinder service, boolean allowIsolated, int dumpPriority)250 public static void addService(String name, IBinder service, boolean allowIsolated, 251 int dumpPriority) { 252 try { 253 getIServiceManager().addService(name, service, allowIsolated, dumpPriority); 254 } catch (RemoteException e) { 255 Log.e(TAG, "error in addService", e); 256 } 257 } 258 259 /** @hide */ addService$ravenwood(String name, IBinder service, boolean allowIsolated, int dumpPriority)260 public static void addService$ravenwood(String name, IBinder service, boolean allowIsolated, 261 int dumpPriority) { 262 synchronized (ServiceManager.class) { 263 // Ravenwood is a single-process environment, so it only needs to store locally 264 Preconditions.requireNonNullViaRavenwoodRule(sCache$ravenwood).put(name, service); 265 } 266 } 267 268 /** 269 * Retrieve an existing service called @a name from the 270 * service manager. Non-blocking. 271 * @hide 272 */ 273 @UnsupportedAppUsage checkService(String name)274 public static IBinder checkService(String name) { 275 try { 276 IBinder service = sCache.get(name); 277 if (service != null) { 278 return service; 279 } else { 280 return Binder.allowBlocking(getIServiceManager().checkService(name)); 281 } 282 } catch (RemoteException e) { 283 Log.e(TAG, "error in checkService", e); 284 return null; 285 } 286 } 287 288 /** 289 * Returns whether the specified service is declared. 290 * 291 * @return true if the service is declared somewhere (eg. VINTF manifest) and 292 * waitForService should always be able to return the service. 293 */ isDeclared(@onNull String name)294 public static boolean isDeclared(@NonNull String name) { 295 try { 296 return getIServiceManager().isDeclared(name); 297 } catch (RemoteException | SecurityException e) { 298 Log.e(TAG, "error in isDeclared", e); 299 return false; 300 } 301 } 302 303 /** 304 * Returns an array of all declared instances for a particular interface. 305 * 306 * For instance, if 'android.foo.IFoo/foo' is declared (e.g. in VINTF 307 * manifest), and 'android.foo.IFoo' is passed here, then ["foo"] would be 308 * returned. 309 * 310 * @hide 311 */ 312 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) 313 @NonNull getDeclaredInstances(@onNull String iface)314 public static String[] getDeclaredInstances(@NonNull String iface) { 315 try { 316 return getIServiceManager().getDeclaredInstances(iface); 317 } catch (RemoteException e) { 318 Log.e(TAG, "error in getDeclaredInstances", e); 319 throw e.rethrowFromSystemServer(); 320 } 321 } 322 323 /** 324 * Returns the specified service from the service manager. 325 * 326 * If the service is not running, servicemanager will attempt to start it, and this function 327 * will wait for it to be ready. 328 * 329 * @return {@code null} only if there are permission problems or fatal errors. 330 * @hide 331 */ waitForService(@onNull String name)332 public static IBinder waitForService(@NonNull String name) { 333 return Binder.allowBlocking(waitForServiceNative(name)); 334 } 335 waitForServiceNative(@onNull String name)336 private static native IBinder waitForServiceNative(@NonNull String name); 337 338 /** 339 * Returns the specified service from the service manager, if declared. 340 * 341 * If the service is not running, servicemanager will attempt to start it, and this function 342 * will wait for it to be ready. 343 * 344 * @throws SecurityException if the process does not have the permissions to check 345 * isDeclared() for the service. 346 * @return {@code null} if the service is not declared in the manifest, or if there 347 * are fatal errors. 348 * @hide 349 */ 350 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) waitForDeclaredService(@onNull String name)351 @Nullable public static IBinder waitForDeclaredService(@NonNull String name) { 352 return isDeclared(name) ? waitForService(name) : null; 353 } 354 355 /** 356 * Register callback for service registration notifications. 357 * 358 * @throws RemoteException for underlying error. 359 * @hide 360 */ registerForNotifications( @onNull String name, @NonNull IServiceCallback callback)361 public static void registerForNotifications( 362 @NonNull String name, @NonNull IServiceCallback callback) throws RemoteException { 363 getIServiceManager().registerForNotifications(name, callback); 364 } 365 366 /** 367 * Return a list of all currently running services. 368 * @return an array of all currently running services, or <code>null</code> in 369 * case of an exception 370 * @hide 371 */ 372 @UnsupportedAppUsage listServices()373 public static String[] listServices() { 374 try { 375 return getIServiceManager().listServices(IServiceManager.DUMP_FLAG_PRIORITY_ALL); 376 } catch (RemoteException e) { 377 Log.e(TAG, "error in listServices", e); 378 return null; 379 } 380 } 381 382 /** 383 * Get service debug info. 384 * @return an array of information for each service (like listServices, but with PIDs) 385 * @hide 386 */ getServiceDebugInfo()387 public static ServiceDebugInfo[] getServiceDebugInfo() { 388 try { 389 return getIServiceManager().getServiceDebugInfo(); 390 } catch (RemoteException e) { 391 Log.e(TAG, "error in getServiceDebugInfo", e); 392 return null; 393 } 394 } 395 396 /** 397 * This is only intended to be called when the process is first being brought 398 * up and bound by the activity manager. There is only one thread in the process 399 * at that time, so no locking is done. 400 * 401 * @param cache the cache of service references 402 * @hide 403 */ initServiceCache(Map<String, IBinder> cache)404 public static void initServiceCache(Map<String, IBinder> cache) { 405 if (sCache.size() != 0) { 406 throw new IllegalStateException("setServiceCache may only be called once"); 407 } 408 sCache.putAll(cache); 409 } 410 411 /** 412 * Exception thrown when no service published for given name. This might be 413 * thrown early during boot before certain services have published 414 * themselves. 415 * 416 * @hide 417 */ 418 @android.ravenwood.annotation.RavenwoodKeepWholeClass 419 public static class ServiceNotFoundException extends Exception { ServiceNotFoundException(String name)420 public ServiceNotFoundException(String name) { 421 super("No service published for: " + name); 422 } 423 } 424 rawGetService(String name)425 private static IBinder rawGetService(String name) throws RemoteException { 426 final long start = sStatLogger.getTime(); 427 428 final IBinder binder = getIServiceManager().getService(name); 429 430 final int time = (int) sStatLogger.logDurationStat(Stats.GET_SERVICE, start); 431 432 final int myUid = Process.myUid(); 433 final boolean isCore = UserHandle.isCore(myUid); 434 435 final long slowThreshold = isCore 436 ? GET_SERVICE_SLOW_THRESHOLD_US_CORE 437 : GET_SERVICE_SLOW_THRESHOLD_US_NON_CORE; 438 439 synchronized (sLock) { 440 sGetServiceAccumulatedUs += time; 441 sGetServiceAccumulatedCallCount++; 442 443 final long nowUptime = SystemClock.uptimeMillis(); 444 445 // Was a slow call? 446 if (time >= slowThreshold) { 447 // We do a slow log: 448 // - At most once in every SLOW_LOG_INTERVAL_MS 449 // - OR it was slower than the previously logged slow call. 450 if ((nowUptime > (sLastSlowLogUptime + SLOW_LOG_INTERVAL_MS)) 451 || (sLastSlowLogActualTime < time)) { 452 EventLogTags.writeServiceManagerSlow(time / 1000, name); 453 454 sLastSlowLogUptime = nowUptime; 455 sLastSlowLogActualTime = time; 456 } 457 } 458 459 // Every GET_SERVICE_LOG_EVERY_CALLS calls, log the total time spent in getService(). 460 461 final int logInterval = isCore 462 ? GET_SERVICE_LOG_EVERY_CALLS_CORE 463 : GET_SERVICE_LOG_EVERY_CALLS_NON_CORE; 464 465 if ((sGetServiceAccumulatedCallCount >= logInterval) 466 && (nowUptime >= (sLastStatsLogUptime + STATS_LOG_INTERVAL_MS))) { 467 468 EventLogTags.writeServiceManagerStats( 469 sGetServiceAccumulatedCallCount, // Total # of getService() calls. 470 sGetServiceAccumulatedUs / 1000, // Total time spent in getService() calls. 471 (int) (nowUptime - sLastStatsLogUptime)); // Uptime duration since last log. 472 sGetServiceAccumulatedCallCount = 0; 473 sGetServiceAccumulatedUs = 0; 474 sLastStatsLogUptime = nowUptime; 475 } 476 } 477 return binder; 478 } 479 } 480