1/*
2 * Copyright (C) 2006 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 java.util.ArrayList;
20
21
22/**
23 * Native implementation of the service manager.  Most clients will only
24 * care about getDefault() and possibly asInterface().
25 * @hide
26 */
27public abstract class ServiceManagerNative extends Binder implements IServiceManager
28{
29    /**
30     * Cast a Binder object into a service manager interface, generating
31     * a proxy if needed.
32     */
33    static public IServiceManager asInterface(IBinder obj)
34    {
35        if (obj == null) {
36            return null;
37        }
38        IServiceManager in =
39            (IServiceManager)obj.queryLocalInterface(descriptor);
40        if (in != null) {
41            return in;
42        }
43
44        return new ServiceManagerProxy(obj);
45    }
46
47    public ServiceManagerNative()
48    {
49        attachInterface(this, descriptor);
50    }
51
52    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
53    {
54        try {
55            switch (code) {
56                case IServiceManager.GET_SERVICE_TRANSACTION: {
57                    data.enforceInterface(IServiceManager.descriptor);
58                    String name = data.readString();
59                    IBinder service = getService(name);
60                    reply.writeStrongBinder(service);
61                    return true;
62                }
63
64                case IServiceManager.CHECK_SERVICE_TRANSACTION: {
65                    data.enforceInterface(IServiceManager.descriptor);
66                    String name = data.readString();
67                    IBinder service = checkService(name);
68                    reply.writeStrongBinder(service);
69                    return true;
70                }
71
72                case IServiceManager.ADD_SERVICE_TRANSACTION: {
73                    data.enforceInterface(IServiceManager.descriptor);
74                    String name = data.readString();
75                    IBinder service = data.readStrongBinder();
76                    boolean allowIsolated = data.readInt() != 0;
77                    int dumpPriority = data.readInt();
78                    addService(name, service, allowIsolated, dumpPriority);
79                    return true;
80                }
81
82                case IServiceManager.LIST_SERVICES_TRANSACTION: {
83                    data.enforceInterface(IServiceManager.descriptor);
84                    int dumpPriority = data.readInt();
85                    String[] list = listServices(dumpPriority);
86                    reply.writeStringArray(list);
87                    return true;
88                }
89
90                case IServiceManager.SET_PERMISSION_CONTROLLER_TRANSACTION: {
91                    data.enforceInterface(IServiceManager.descriptor);
92                    IPermissionController controller =
93                            IPermissionController.Stub.asInterface(
94                                    data.readStrongBinder());
95                    setPermissionController(controller);
96                    return true;
97                }
98            }
99        } catch (RemoteException e) {
100        }
101
102        return false;
103    }
104
105    public IBinder asBinder()
106    {
107        return this;
108    }
109}
110
111class ServiceManagerProxy implements IServiceManager {
112    public ServiceManagerProxy(IBinder remote) {
113        mRemote = remote;
114    }
115
116    public IBinder asBinder() {
117        return mRemote;
118    }
119
120    public IBinder getService(String name) throws RemoteException {
121        Parcel data = Parcel.obtain();
122        Parcel reply = Parcel.obtain();
123        data.writeInterfaceToken(IServiceManager.descriptor);
124        data.writeString(name);
125        mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
126        IBinder binder = reply.readStrongBinder();
127        reply.recycle();
128        data.recycle();
129        return binder;
130    }
131
132    public IBinder checkService(String name) throws RemoteException {
133        Parcel data = Parcel.obtain();
134        Parcel reply = Parcel.obtain();
135        data.writeInterfaceToken(IServiceManager.descriptor);
136        data.writeString(name);
137        mRemote.transact(CHECK_SERVICE_TRANSACTION, data, reply, 0);
138        IBinder binder = reply.readStrongBinder();
139        reply.recycle();
140        data.recycle();
141        return binder;
142    }
143
144    public void addService(String name, IBinder service, boolean allowIsolated, int dumpPriority)
145            throws RemoteException {
146        Parcel data = Parcel.obtain();
147        Parcel reply = Parcel.obtain();
148        data.writeInterfaceToken(IServiceManager.descriptor);
149        data.writeString(name);
150        data.writeStrongBinder(service);
151        data.writeInt(allowIsolated ? 1 : 0);
152        data.writeInt(dumpPriority);
153        mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
154        reply.recycle();
155        data.recycle();
156    }
157
158    public String[] listServices(int dumpPriority) throws RemoteException {
159        ArrayList<String> services = new ArrayList<String>();
160        int n = 0;
161        while (true) {
162            Parcel data = Parcel.obtain();
163            Parcel reply = Parcel.obtain();
164            data.writeInterfaceToken(IServiceManager.descriptor);
165            data.writeInt(n);
166            data.writeInt(dumpPriority);
167            n++;
168            try {
169                boolean res = mRemote.transact(LIST_SERVICES_TRANSACTION, data, reply, 0);
170                if (!res) {
171                    break;
172                }
173            } catch (RuntimeException e) {
174                // The result code that is returned by the C++ code can
175                // cause the call to throw an exception back instead of
176                // returning a nice result...  so eat it here and go on.
177                break;
178            }
179            services.add(reply.readString());
180            reply.recycle();
181            data.recycle();
182        }
183        String[] array = new String[services.size()];
184        services.toArray(array);
185        return array;
186    }
187
188    public void setPermissionController(IPermissionController controller)
189            throws RemoteException {
190        Parcel data = Parcel.obtain();
191        Parcel reply = Parcel.obtain();
192        data.writeInterfaceToken(IServiceManager.descriptor);
193        data.writeStrongBinder(controller.asBinder());
194        mRemote.transact(SET_PERMISSION_CONTROLLER_TRANSACTION, data, reply, 0);
195        reply.recycle();
196        data.recycle();
197    }
198
199    private IBinder mRemote;
200}
201