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                addService(name, service, allowIsolated);
78                return true;
79            }
80
81            case IServiceManager.LIST_SERVICES_TRANSACTION: {
82                data.enforceInterface(IServiceManager.descriptor);
83                String[] list = listServices();
84                reply.writeStringArray(list);
85                return true;
86            }
87
88            case IServiceManager.SET_PERMISSION_CONTROLLER_TRANSACTION: {
89                data.enforceInterface(IServiceManager.descriptor);
90                IPermissionController controller
91                        = IPermissionController.Stub.asInterface(
92                                data.readStrongBinder());
93                setPermissionController(controller);
94                return true;
95            }
96            }
97        } catch (RemoteException e) {
98        }
99
100        return false;
101    }
102
103    public IBinder asBinder()
104    {
105        return this;
106    }
107}
108
109class ServiceManagerProxy implements IServiceManager {
110    public ServiceManagerProxy(IBinder remote) {
111        mRemote = remote;
112    }
113
114    public IBinder asBinder() {
115        return mRemote;
116    }
117
118    public IBinder getService(String name) throws RemoteException {
119        Parcel data = Parcel.obtain();
120        Parcel reply = Parcel.obtain();
121        data.writeInterfaceToken(IServiceManager.descriptor);
122        data.writeString(name);
123        mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
124        IBinder binder = reply.readStrongBinder();
125        reply.recycle();
126        data.recycle();
127        return binder;
128    }
129
130    public IBinder checkService(String name) throws RemoteException {
131        Parcel data = Parcel.obtain();
132        Parcel reply = Parcel.obtain();
133        data.writeInterfaceToken(IServiceManager.descriptor);
134        data.writeString(name);
135        mRemote.transact(CHECK_SERVICE_TRANSACTION, data, reply, 0);
136        IBinder binder = reply.readStrongBinder();
137        reply.recycle();
138        data.recycle();
139        return binder;
140    }
141
142    public void addService(String name, IBinder service, boolean allowIsolated)
143            throws RemoteException {
144        Parcel data = Parcel.obtain();
145        Parcel reply = Parcel.obtain();
146        data.writeInterfaceToken(IServiceManager.descriptor);
147        data.writeString(name);
148        data.writeStrongBinder(service);
149        data.writeInt(allowIsolated ? 1 : 0);
150        mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
151        reply.recycle();
152        data.recycle();
153    }
154
155    public String[] listServices() throws RemoteException {
156        ArrayList<String> services = new ArrayList<String>();
157        int n = 0;
158        while (true) {
159            Parcel data = Parcel.obtain();
160            Parcel reply = Parcel.obtain();
161            data.writeInterfaceToken(IServiceManager.descriptor);
162            data.writeInt(n);
163            n++;
164            try {
165                boolean res = mRemote.transact(LIST_SERVICES_TRANSACTION, data, reply, 0);
166                if (!res) {
167                    break;
168                }
169            } catch (RuntimeException e) {
170                // The result code that is returned by the C++ code can
171                // cause the call to throw an exception back instead of
172                // returning a nice result...  so eat it here and go on.
173                break;
174            }
175            services.add(reply.readString());
176            reply.recycle();
177            data.recycle();
178        }
179        String[] array = new String[services.size()];
180        services.toArray(array);
181        return array;
182    }
183
184    public void setPermissionController(IPermissionController controller)
185            throws RemoteException {
186        Parcel data = Parcel.obtain();
187        Parcel reply = Parcel.obtain();
188        data.writeInterfaceToken(IServiceManager.descriptor);
189        data.writeStrongBinder(controller.asBinder());
190        mRemote.transact(SET_PERMISSION_CONTROLLER_TRANSACTION, data, reply, 0);
191        reply.recycle();
192        data.recycle();
193    }
194
195    private IBinder mRemote;
196}
197