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.compat.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 ServiceManager()105 public ServiceManager() { 106 } 107 108 @UnsupportedAppUsage getIServiceManager()109 private static IServiceManager getIServiceManager() { 110 if (sServiceManager != null) { 111 return sServiceManager; 112 } 113 114 // Find the service manager 115 sServiceManager = ServiceManagerNative 116 .asInterface(Binder.allowBlocking(BinderInternal.getContextObject())); 117 return sServiceManager; 118 } 119 120 /** 121 * Returns a reference to a service with the given name. 122 * 123 * @param name the name of the service to get 124 * @return a reference to the service, or <code>null</code> if the service doesn't exist 125 */ 126 @UnsupportedAppUsage getService(String name)127 public static IBinder getService(String name) { 128 try { 129 IBinder service = sCache.get(name); 130 if (service != null) { 131 return service; 132 } else { 133 return Binder.allowBlocking(rawGetService(name)); 134 } 135 } catch (RemoteException e) { 136 Log.e(TAG, "error in getService", e); 137 } 138 return null; 139 } 140 141 /** 142 * Returns a reference to a service with the given name, or throws 143 * {@link NullPointerException} if none is found. 144 * 145 * @hide 146 */ getServiceOrThrow(String name)147 public static IBinder getServiceOrThrow(String name) throws ServiceNotFoundException { 148 final IBinder binder = getService(name); 149 if (binder != null) { 150 return binder; 151 } else { 152 throw new ServiceNotFoundException(name); 153 } 154 } 155 156 /** 157 * Place a new @a service called @a name into the service 158 * manager. 159 * 160 * @param name the name of the new service 161 * @param service the service object 162 */ 163 @UnsupportedAppUsage addService(String name, IBinder service)164 public static void addService(String name, IBinder service) { 165 addService(name, service, false, IServiceManager.DUMP_FLAG_PRIORITY_DEFAULT); 166 } 167 168 /** 169 * Place a new @a service called @a name into the service 170 * manager. 171 * 172 * @param name the name of the new service 173 * @param service the service object 174 * @param allowIsolated set to true to allow isolated sandboxed processes 175 * to access this service 176 */ 177 @UnsupportedAppUsage addService(String name, IBinder service, boolean allowIsolated)178 public static void addService(String name, IBinder service, boolean allowIsolated) { 179 addService(name, service, allowIsolated, IServiceManager.DUMP_FLAG_PRIORITY_DEFAULT); 180 } 181 182 /** 183 * Place a new @a service called @a name into the service 184 * manager. 185 * 186 * @param name the name of the new service 187 * @param service the service object 188 * @param allowIsolated set to true to allow isolated sandboxed processes 189 * @param dumpPriority supported dump priority levels as a bitmask 190 * to access this service 191 */ 192 @UnsupportedAppUsage addService(String name, IBinder service, boolean allowIsolated, int dumpPriority)193 public static void addService(String name, IBinder service, boolean allowIsolated, 194 int dumpPriority) { 195 try { 196 getIServiceManager().addService(name, service, allowIsolated, dumpPriority); 197 } catch (RemoteException e) { 198 Log.e(TAG, "error in addService", e); 199 } 200 } 201 202 /** 203 * Retrieve an existing service called @a name from the 204 * service manager. Non-blocking. 205 */ 206 @UnsupportedAppUsage checkService(String name)207 public static IBinder checkService(String name) { 208 try { 209 IBinder service = sCache.get(name); 210 if (service != null) { 211 return service; 212 } else { 213 return Binder.allowBlocking(getIServiceManager().checkService(name)); 214 } 215 } catch (RemoteException e) { 216 Log.e(TAG, "error in checkService", e); 217 return null; 218 } 219 } 220 221 /** 222 * Return a list of all currently running services. 223 * @return an array of all currently running services, or <code>null</code> in 224 * case of an exception 225 */ 226 @UnsupportedAppUsage listServices()227 public static String[] listServices() { 228 try { 229 return getIServiceManager().listServices(IServiceManager.DUMP_FLAG_PRIORITY_ALL); 230 } catch (RemoteException e) { 231 Log.e(TAG, "error in listServices", e); 232 return null; 233 } 234 } 235 236 /** 237 * This is only intended to be called when the process is first being brought 238 * up and bound by the activity manager. There is only one thread in the process 239 * at that time, so no locking is done. 240 * 241 * @param cache the cache of service references 242 * @hide 243 */ initServiceCache(Map<String, IBinder> cache)244 public static void initServiceCache(Map<String, IBinder> cache) { 245 if (sCache.size() != 0) { 246 throw new IllegalStateException("setServiceCache may only be called once"); 247 } 248 sCache.putAll(cache); 249 } 250 251 /** 252 * Exception thrown when no service published for given name. This might be 253 * thrown early during boot before certain services have published 254 * themselves. 255 * 256 * @hide 257 */ 258 public static class ServiceNotFoundException extends Exception { ServiceNotFoundException(String name)259 public ServiceNotFoundException(String name) { 260 super("No service published for: " + name); 261 } 262 } 263 rawGetService(String name)264 private static IBinder rawGetService(String name) throws RemoteException { 265 final long start = sStatLogger.getTime(); 266 267 final IBinder binder = getIServiceManager().getService(name); 268 269 final int time = (int) sStatLogger.logDurationStat(Stats.GET_SERVICE, start); 270 271 final int myUid = Process.myUid(); 272 final boolean isCore = UserHandle.isCore(myUid); 273 274 final long slowThreshold = isCore 275 ? GET_SERVICE_SLOW_THRESHOLD_US_CORE 276 : GET_SERVICE_SLOW_THRESHOLD_US_NON_CORE; 277 278 synchronized (sLock) { 279 sGetServiceAccumulatedUs += time; 280 sGetServiceAccumulatedCallCount++; 281 282 final long nowUptime = SystemClock.uptimeMillis(); 283 284 // Was a slow call? 285 if (time >= slowThreshold) { 286 // We do a slow log: 287 // - At most once in every SLOW_LOG_INTERVAL_MS 288 // - OR it was slower than the previously logged slow call. 289 if ((nowUptime > (sLastSlowLogUptime + SLOW_LOG_INTERVAL_MS)) 290 || (sLastSlowLogActualTime < time)) { 291 EventLogTags.writeServiceManagerSlow(time / 1000, name); 292 293 sLastSlowLogUptime = nowUptime; 294 sLastSlowLogActualTime = time; 295 } 296 } 297 298 // Every GET_SERVICE_LOG_EVERY_CALLS calls, log the total time spent in getService(). 299 300 final int logInterval = isCore 301 ? GET_SERVICE_LOG_EVERY_CALLS_CORE 302 : GET_SERVICE_LOG_EVERY_CALLS_NON_CORE; 303 304 if ((sGetServiceAccumulatedCallCount >= logInterval) 305 && (nowUptime >= (sLastStatsLogUptime + STATS_LOG_INTERVAL_MS))) { 306 307 EventLogTags.writeServiceManagerStats( 308 sGetServiceAccumulatedCallCount, // Total # of getService() calls. 309 sGetServiceAccumulatedUs / 1000, // Total time spent in getService() calls. 310 (int) (nowUptime - sLastStatsLogUptime)); // Uptime duration since last log. 311 sGetServiceAccumulatedCallCount = 0; 312 sGetServiceAccumulatedUs = 0; 313 sLastStatsLogUptime = nowUptime; 314 } 315 } 316 return binder; 317 } 318 } 319