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