• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.util.Log;
20 
21 import com.android.internal.annotations.GuardedBy;
22 import com.android.internal.os.BinderInternal;
23 import com.android.internal.util.StatLogger;
24 
25 import java.util.HashMap;
26 import java.util.Map;
27 
28 /** @hide */
29 public 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 
getIServiceManager()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      */
getService(String name)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      */
getServiceOrThrow(String name)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      */
addService(String name, IBinder service)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      */
addService(String name, IBinder service, boolean allowIsolated)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      */
addService(String name, IBinder service, boolean allowIsolated, int dumpPriority)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      */
checkService(String name)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      */
listServices()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      */
initServiceCache(Map<String, IBinder> cache)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 {
ServiceNotFoundException(String name)245         public ServiceNotFoundException(String name) {
246             super("No service published for: " + name);
247         }
248     }
249 
rawGetService(String name)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