ServiceManager.java revision 49392d335af8559169238bb9cb4fc2911192adea
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
17package android.os;
18
19import android.util.Log;
20
21import com.android.internal.annotations.GuardedBy;
22import com.android.internal.os.BinderInternal;
23import com.android.internal.util.StatLogger;
24
25import java.util.HashMap;
26import java.util.Map;
27
28/** @hide */
29public 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
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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 {
245        public ServiceNotFoundException(String name) {
246            super("No service published for: " + name);
247        }
248    }
249
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