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.os.BinderInternal;
22
23import java.util.HashMap;
24import java.util.Map;
25
26/** @hide */
27public final class ServiceManager {
28    private static final String TAG = "ServiceManager";
29
30    private static IServiceManager sServiceManager;
31    private static HashMap<String, IBinder> sCache = new HashMap<String, IBinder>();
32
33    private static IServiceManager getIServiceManager() {
34        if (sServiceManager != null) {
35            return sServiceManager;
36        }
37
38        // Find the service manager
39        sServiceManager = ServiceManagerNative
40                .asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
41        return sServiceManager;
42    }
43
44    /**
45     * Returns a reference to a service with the given name.
46     *
47     * @param name the name of the service to get
48     * @return a reference to the service, or <code>null</code> if the service doesn't exist
49     */
50    public static IBinder getService(String name) {
51        try {
52            IBinder service = sCache.get(name);
53            if (service != null) {
54                return service;
55            } else {
56                return Binder.allowBlocking(getIServiceManager().getService(name));
57            }
58        } catch (RemoteException e) {
59            Log.e(TAG, "error in getService", e);
60        }
61        return null;
62    }
63
64    /**
65     * Returns a reference to a service with the given name, or throws
66     * {@link NullPointerException} if none is found.
67     *
68     * @hide
69     */
70    public static IBinder getServiceOrThrow(String name) throws ServiceNotFoundException {
71        final IBinder binder = getService(name);
72        if (binder != null) {
73            return binder;
74        } else {
75            throw new ServiceNotFoundException(name);
76        }
77    }
78
79    /**
80     * Place a new @a service called @a name into the service
81     * manager.
82     *
83     * @param name the name of the new service
84     * @param service the service object
85     */
86    public static void addService(String name, IBinder service) {
87        try {
88            getIServiceManager().addService(name, service, false);
89        } catch (RemoteException e) {
90            Log.e(TAG, "error in addService", e);
91        }
92    }
93
94    /**
95     * Place a new @a service called @a name into the service
96     * manager.
97     *
98     * @param name the name of the new service
99     * @param service the service object
100     * @param allowIsolated set to true to allow isolated sandboxed processes
101     * to access this service
102     */
103    public static void addService(String name, IBinder service, boolean allowIsolated) {
104        try {
105            getIServiceManager().addService(name, service, allowIsolated);
106        } catch (RemoteException e) {
107            Log.e(TAG, "error in addService", e);
108        }
109    }
110
111    /**
112     * Retrieve an existing service called @a name from the
113     * service manager.  Non-blocking.
114     */
115    public static IBinder checkService(String name) {
116        try {
117            IBinder service = sCache.get(name);
118            if (service != null) {
119                return service;
120            } else {
121                return Binder.allowBlocking(getIServiceManager().checkService(name));
122            }
123        } catch (RemoteException e) {
124            Log.e(TAG, "error in checkService", e);
125            return null;
126        }
127    }
128
129    /**
130     * Return a list of all currently running services.
131     * @return an array of all currently running services, or <code>null</code> in
132     * case of an exception
133     */
134    public static String[] listServices() {
135        try {
136            return getIServiceManager().listServices();
137        } catch (RemoteException e) {
138            Log.e(TAG, "error in listServices", e);
139            return null;
140        }
141    }
142
143    /**
144     * This is only intended to be called when the process is first being brought
145     * up and bound by the activity manager. There is only one thread in the process
146     * at that time, so no locking is done.
147     *
148     * @param cache the cache of service references
149     * @hide
150     */
151    public static void initServiceCache(Map<String, IBinder> cache) {
152        if (sCache.size() != 0) {
153            throw new IllegalStateException("setServiceCache may only be called once");
154        }
155        sCache.putAll(cache);
156    }
157
158    /**
159     * Exception thrown when no service published for given name. This might be
160     * thrown early during boot before certain services have published
161     * themselves.
162     *
163     * @hide
164     */
165    public static class ServiceNotFoundException extends Exception {
166        public ServiceNotFoundException(String name) {
167            super("No service published for: " + name);
168        }
169    }
170}
171