summaryrefslogtreecommitdiff
path: root/android/os/ServiceManager.java
diff options
context:
space:
mode:
authorJustin Klaassen <justinklaassen@google.com>2018-04-15 00:41:15 -0400
committerJustin Klaassen <justinklaassen@google.com>2018-04-15 00:41:15 -0400
commitb8042fc9b036db0a6692ca853428fc6ab1e60892 (patch)
tree82669ea5d75238758e22d379a42baeada526219e /android/os/ServiceManager.java
parent4d01eeaffaa720e4458a118baa137a11614f00f7 (diff)
downloadandroid-28-b8042fc9b036db0a6692ca853428fc6ab1e60892.tar.gz
/google/data/ro/projects/android/fetch_artifact \ --bid 4719250 \ --target sdk_phone_armv7-win_sdk \ sdk-repo-linux-sources-4719250.zip AndroidVersion.ApiLevel has been modified to appear as 28 Change-Id: I9ec0a12c9251b8449dba0d86b0cfdbcca16b0a7c
Diffstat (limited to 'android/os/ServiceManager.java')
-rw-r--r--android/os/ServiceManager.java229
1 files changed, 219 insertions, 10 deletions
diff --git a/android/os/ServiceManager.java b/android/os/ServiceManager.java
index 34c78455..165276d5 100644
--- a/android/os/ServiceManager.java
+++ b/android/os/ServiceManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,9 +16,98 @@
package android.os;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.BinderInternal;
+import com.android.internal.util.StatLogger;
+
+import java.util.HashMap;
import java.util.Map;
+/** @hide */
public final class ServiceManager {
+ private static final String TAG = "ServiceManager";
+ private static final Object sLock = new Object();
+
+ private static IServiceManager sServiceManager;
+
+ /**
+ * Cache for the "well known" services, such as WM and AM.
+ */
+ private static HashMap<String, IBinder> sCache = new HashMap<String, IBinder>();
+
+ /**
+ * We do the "slow log" at most once every this interval.
+ */
+ private static final int SLOW_LOG_INTERVAL_MS = 5000;
+
+ /**
+ * We do the "stats log" at most once every this interval.
+ */
+ private static final int STATS_LOG_INTERVAL_MS = 5000;
+
+ /**
+ * Threshold in uS for a "slow" call, used on core UIDs. We use a more relax value to
+ * avoid logspam.
+ */
+ private static final long GET_SERVICE_SLOW_THRESHOLD_US_CORE =
+ SystemProperties.getInt("debug.servicemanager.slow_call_core_ms", 10) * 1000;
+
+ /**
+ * Threshold in uS for a "slow" call, used on non-core UIDs. We use a more relax value to
+ * avoid logspam.
+ */
+ private static final long GET_SERVICE_SLOW_THRESHOLD_US_NON_CORE =
+ SystemProperties.getInt("debug.servicemanager.slow_call_ms", 50) * 1000;
+
+ /**
+ * We log stats logging ever this many getService() calls.
+ */
+ private static final int GET_SERVICE_LOG_EVERY_CALLS_CORE =
+ SystemProperties.getInt("debug.servicemanager.log_calls_core", 100);
+
+ /**
+ * We log stats logging ever this many getService() calls.
+ */
+ private static final int GET_SERVICE_LOG_EVERY_CALLS_NON_CORE =
+ SystemProperties.getInt("debug.servicemanager.log_calls", 200);
+
+ @GuardedBy("sLock")
+ private static int sGetServiceAccumulatedUs;
+
+ @GuardedBy("sLock")
+ private static int sGetServiceAccumulatedCallCount;
+
+ @GuardedBy("sLock")
+ private static long sLastStatsLogUptime;
+
+ @GuardedBy("sLock")
+ private static long sLastSlowLogUptime;
+
+ @GuardedBy("sLock")
+ private static long sLastSlowLogActualTime;
+
+ interface Stats {
+ int GET_SERVICE = 0;
+
+ int COUNT = GET_SERVICE + 1;
+ }
+
+ public static final StatLogger sStatLogger = new StatLogger(new String[] {
+ "getService()",
+ });
+
+ private static IServiceManager getIServiceManager() {
+ if (sServiceManager != null) {
+ return sServiceManager;
+ }
+
+ // Find the service manager
+ sServiceManager = ServiceManagerNative
+ .asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
+ return sServiceManager;
+ }
/**
* Returns a reference to a service with the given name.
@@ -27,14 +116,32 @@ public final class ServiceManager {
* @return a reference to the service, or <code>null</code> if the service doesn't exist
*/
public static IBinder getService(String name) {
+ try {
+ IBinder service = sCache.get(name);
+ if (service != null) {
+ return service;
+ } else {
+ return Binder.allowBlocking(rawGetService(name));
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "error in getService", e);
+ }
return null;
}
/**
- * Is not supposed to return null, but that is fine for layoutlib.
+ * Returns a reference to a service with the given name, or throws
+ * {@link NullPointerException} if none is found.
+ *
+ * @hide
*/
public static IBinder getServiceOrThrow(String name) throws ServiceNotFoundException {
- throw new ServiceNotFoundException(name);
+ final IBinder binder = getService(name);
+ if (binder != null) {
+ return binder;
+ } else {
+ throw new ServiceNotFoundException(name);
+ }
}
/**
@@ -45,7 +152,39 @@ public final class ServiceManager {
* @param service the service object
*/
public static void addService(String name, IBinder service) {
- // pass
+ addService(name, service, false, IServiceManager.DUMP_FLAG_PRIORITY_DEFAULT);
+ }
+
+ /**
+ * Place a new @a service called @a name into the service
+ * manager.
+ *
+ * @param name the name of the new service
+ * @param service the service object
+ * @param allowIsolated set to true to allow isolated sandboxed processes
+ * to access this service
+ */
+ public static void addService(String name, IBinder service, boolean allowIsolated) {
+ addService(name, service, allowIsolated, IServiceManager.DUMP_FLAG_PRIORITY_DEFAULT);
+ }
+
+ /**
+ * Place a new @a service called @a name into the service
+ * manager.
+ *
+ * @param name the name of the new service
+ * @param service the service object
+ * @param allowIsolated set to true to allow isolated sandboxed processes
+ * @param dumpPriority supported dump priority levels as a bitmask
+ * to access this service
+ */
+ public static void addService(String name, IBinder service, boolean allowIsolated,
+ int dumpPriority) {
+ try {
+ getIServiceManager().addService(name, service, allowIsolated, dumpPriority);
+ } catch (RemoteException e) {
+ Log.e(TAG, "error in addService", e);
+ }
}
/**
@@ -53,7 +192,17 @@ public final class ServiceManager {
* service manager. Non-blocking.
*/
public static IBinder checkService(String name) {
- return null;
+ try {
+ IBinder service = sCache.get(name);
+ if (service != null) {
+ return service;
+ } else {
+ return Binder.allowBlocking(getIServiceManager().checkService(name));
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "error in checkService", e);
+ return null;
+ }
}
/**
@@ -62,9 +211,12 @@ public final class ServiceManager {
* case of an exception
*/
public static String[] listServices() {
- // actual implementation returns null sometimes, so it's ok
- // to return null instead of an empty list.
- return null;
+ try {
+ return getIServiceManager().listServices(IServiceManager.DUMP_FLAG_PRIORITY_ALL);
+ } catch (RemoteException e) {
+ Log.e(TAG, "error in listServices", e);
+ return null;
+ }
}
/**
@@ -76,7 +228,10 @@ public final class ServiceManager {
* @hide
*/
public static void initServiceCache(Map<String, IBinder> cache) {
- // pass
+ if (sCache.size() != 0) {
+ throw new IllegalStateException("setServiceCache may only be called once");
+ }
+ sCache.putAll(cache);
}
/**
@@ -87,9 +242,63 @@ public final class ServiceManager {
* @hide
*/
public static class ServiceNotFoundException extends Exception {
- // identical to the original implementation
public ServiceNotFoundException(String name) {
super("No service published for: " + name);
}
}
+
+ private static IBinder rawGetService(String name) throws RemoteException {
+ final long start = sStatLogger.getTime();
+
+ final IBinder binder = getIServiceManager().getService(name);
+
+ final int time = (int) sStatLogger.logDurationStat(Stats.GET_SERVICE, start);
+
+ final int myUid = Process.myUid();
+ final boolean isCore = UserHandle.isCore(myUid);
+
+ final long slowThreshold = isCore
+ ? GET_SERVICE_SLOW_THRESHOLD_US_CORE
+ : GET_SERVICE_SLOW_THRESHOLD_US_NON_CORE;
+
+ synchronized (sLock) {
+ sGetServiceAccumulatedUs += time;
+ sGetServiceAccumulatedCallCount++;
+
+ final long nowUptime = SystemClock.uptimeMillis();
+
+ // Was a slow call?
+ if (time >= slowThreshold) {
+ // We do a slow log:
+ // - At most once in every SLOW_LOG_INTERVAL_MS
+ // - OR it was slower than the previously logged slow call.
+ if ((nowUptime > (sLastSlowLogUptime + SLOW_LOG_INTERVAL_MS))
+ || (sLastSlowLogActualTime < time)) {
+ EventLogTags.writeServiceManagerSlow(time / 1000, name);
+
+ sLastSlowLogUptime = nowUptime;
+ sLastSlowLogActualTime = time;
+ }
+ }
+
+ // Every GET_SERVICE_LOG_EVERY_CALLS calls, log the total time spent in getService().
+
+ final int logInterval = isCore
+ ? GET_SERVICE_LOG_EVERY_CALLS_CORE
+ : GET_SERVICE_LOG_EVERY_CALLS_NON_CORE;
+
+ if ((sGetServiceAccumulatedCallCount >= logInterval)
+ && (nowUptime >= (sLastStatsLogUptime + STATS_LOG_INTERVAL_MS))) {
+
+ EventLogTags.writeServiceManagerStats(
+ sGetServiceAccumulatedCallCount, // Total # of getService() calls.
+ sGetServiceAccumulatedUs / 1000, // Total time spent in getService() calls.
+ (int) (nowUptime - sLastStatsLogUptime)); // Uptime duration since last log.
+ sGetServiceAccumulatedCallCount = 0;
+ sGetServiceAccumulatedUs = 0;
+ sLastStatsLogUptime = nowUptime;
+ }
+ }
+ return binder;
+ }
}