1 /*
2 **
3 ** Copyright 2015, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 **     http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17 
18 #define LOG_TAG "BpRadioService"
19 //#define LOG_NDEBUG 0
20 
21 #include <utils/Log.h>
22 #include <utils/Errors.h>
23 
24 #include <stdint.h>
25 #include <sys/types.h>
26 #include <binder/IMemory.h>
27 #include <binder/Parcel.h>
28 #include <binder/IPCThreadState.h>
29 #include <binder/IServiceManager.h>
30 
31 #include <radio/IRadioService.h>
32 #include <radio/IRadio.h>
33 #include <radio/IRadioClient.h>
34 
35 namespace android {
36 
37 enum {
38     LIST_MODULES = IBinder::FIRST_CALL_TRANSACTION,
39     ATTACH,
40 };
41 
42 #define MAX_ITEMS_PER_LIST 1024
43 
44 class BpRadioService: public BpInterface<IRadioService>
45 {
46 public:
BpRadioService(const sp<IBinder> & impl)47     explicit BpRadioService(const sp<IBinder>& impl)
48         : BpInterface<IRadioService>(impl)
49     {
50     }
51 
listModules(struct radio_properties * properties,uint32_t * numModules)52     virtual status_t listModules(struct radio_properties *properties,
53                                  uint32_t *numModules)
54     {
55         if (numModules == NULL || (*numModules != 0 && properties == NULL)) {
56             return BAD_VALUE;
57         }
58         Parcel data, reply;
59         data.writeInterfaceToken(IRadioService::getInterfaceDescriptor());
60         uint32_t numModulesReq = (properties == NULL) ? 0 : *numModules;
61         data.writeInt32(numModulesReq);
62         status_t status = remote()->transact(LIST_MODULES, data, &reply);
63         if (status == NO_ERROR) {
64             status = (status_t)reply.readInt32();
65             *numModules = (uint32_t)reply.readInt32();
66         }
67         ALOGV("listModules() status %d got *numModules %d", status, *numModules);
68         if (status == NO_ERROR) {
69             if (numModulesReq > *numModules) {
70                 numModulesReq = *numModules;
71             }
72             if (numModulesReq > 0) {
73                 reply.read(properties, numModulesReq * sizeof(struct radio_properties));
74             }
75         }
76         return status;
77     }
78 
attach(radio_handle_t handle,const sp<IRadioClient> & client,const struct radio_band_config * config,bool withAudio,sp<IRadio> & radio)79     virtual status_t attach(radio_handle_t handle,
80                             const sp<IRadioClient>& client,
81                             const struct radio_band_config *config,
82                             bool withAudio,
83                             sp<IRadio>& radio)
84     {
85         Parcel data, reply;
86         data.writeInterfaceToken(IRadioService::getInterfaceDescriptor());
87         data.writeInt32(handle);
88         data.writeStrongBinder(IInterface::asBinder(client));
89         ALOGV("attach() config %p withAudio %d region %d type %d",
90               config == NULL ? 0 : config, withAudio,
91               config == NULL ? 0 : config->region,
92               config == NULL ? 0 : config->band.type);
93         if (config == NULL) {
94             data.writeInt32(0);
95         } else {
96             data.writeInt32(1);
97             data.write(config, sizeof(struct radio_band_config));
98         }
99         data.writeInt32(withAudio ? 1 : 0);
100         status_t status = remote()->transact(ATTACH, data, &reply);
101         if (status != NO_ERROR) {
102             return status;
103         }
104         status = reply.readInt32();
105         if (reply.readInt32() != 0) {
106             radio = interface_cast<IRadio>(reply.readStrongBinder());
107         }
108         return status;
109     }
110 };
111 
112 IMPLEMENT_META_INTERFACE(RadioService, "android.hardware.IRadioService");
113 
114 // ----------------------------------------------------------------------
115 
onTransact(uint32_t code,const Parcel & data,Parcel * reply,uint32_t flags)116 status_t BnRadioService::onTransact(
117     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
118 {
119     switch(code) {
120         case LIST_MODULES: {
121             CHECK_INTERFACE(IRadioService, data, reply);
122             uint32_t numModulesReq = data.readInt32();
123             if (numModulesReq > MAX_ITEMS_PER_LIST) {
124                 numModulesReq = MAX_ITEMS_PER_LIST;
125             }
126             uint32_t numModules = numModulesReq;
127             struct radio_properties *properties =
128                     (struct radio_properties *)calloc(numModulesReq,
129                                                       sizeof(struct radio_properties));
130             if (properties == NULL) {
131                 reply->writeInt32(NO_MEMORY);
132                 reply->writeInt32(0);
133                 return NO_ERROR;
134             }
135 
136             status_t status = listModules(properties, &numModules);
137             reply->writeInt32(status);
138             reply->writeInt32(numModules);
139             ALOGV("LIST_MODULES status %d got numModules %d", status, numModules);
140 
141             if (status == NO_ERROR) {
142                 if (numModulesReq > numModules) {
143                     numModulesReq = numModules;
144                 }
145                 reply->write(properties,
146                              numModulesReq * sizeof(struct radio_properties));
147             }
148             free(properties);
149             return NO_ERROR;
150         } break;
151 
152         case ATTACH: {
153             CHECK_INTERFACE(IRadioService, data, reply);
154             radio_handle_t handle = data.readInt32();
155             sp<IRadioClient> client =
156                     interface_cast<IRadioClient>(data.readStrongBinder());
157             struct radio_band_config config;
158             struct radio_band_config *configPtr = NULL;
159             if (data.readInt32() != 0) {
160                 data.read(&config, sizeof(struct radio_band_config));
161                 configPtr = &config;
162             }
163             bool withAudio = data.readInt32() != 0;
164             ALOGV("ATTACH configPtr %p withAudio %d", configPtr, withAudio);
165             sp<IRadio> radio;
166             status_t status = attach(handle, client, configPtr, withAudio, radio);
167             reply->writeInt32(status);
168             if (radio != 0) {
169                 reply->writeInt32(1);
170                 reply->writeStrongBinder(IInterface::asBinder(radio));
171             } else {
172                 reply->writeInt32(0);
173             }
174             return NO_ERROR;
175         } break;
176         default:
177             return BBinder::onTransact(code, data, reply, flags);
178     }
179 }
180 
181 // ----------------------------------------------------------------------------
182 
183 }; // namespace android
184