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//
20#define LOG_NDEBUG 0
21
22#include <utils/Log.h>
23#include <utils/Errors.h>
24
25#include <stdint.h>
26#include <sys/types.h>
27#include <binder/IMemory.h>
28#include <binder/Parcel.h>
29#include <binder/IPCThreadState.h>
30#include <binder/IServiceManager.h>
31
32#include <radio/IRadioService.h>
33#include <radio/IRadio.h>
34#include <radio/IRadioClient.h>
35
36namespace android {
37
38enum {
39    LIST_MODULES = IBinder::FIRST_CALL_TRANSACTION,
40    ATTACH,
41};
42
43#define MAX_ITEMS_PER_LIST 1024
44
45class BpRadioService: public BpInterface<IRadioService>
46{
47public:
48    BpRadioService(const sp<IBinder>& impl)
49        : BpInterface<IRadioService>(impl)
50    {
51    }
52
53    virtual status_t listModules(struct radio_properties *properties,
54                                 uint32_t *numModules)
55    {
56        if (numModules == NULL || (*numModules != 0 && properties == NULL)) {
57            return BAD_VALUE;
58        }
59        Parcel data, reply;
60        data.writeInterfaceToken(IRadioService::getInterfaceDescriptor());
61        unsigned int numModulesReq = (properties == NULL) ? 0 : *numModules;
62        data.writeInt32(numModulesReq);
63        status_t status = remote()->transact(LIST_MODULES, data, &reply);
64        if (status == NO_ERROR) {
65            status = (status_t)reply.readInt32();
66            *numModules = (unsigned int)reply.readInt32();
67        }
68        ALOGV("listModules() status %d got *numModules %d", status, *numModules);
69        if (status == NO_ERROR) {
70            if (numModulesReq > *numModules) {
71                numModulesReq = *numModules;
72            }
73            if (numModulesReq > 0) {
74                reply.read(properties, numModulesReq * sizeof(struct radio_properties));
75            }
76        }
77        return status;
78    }
79
80    virtual status_t attach(radio_handle_t handle,
81                            const sp<IRadioClient>& client,
82                            const struct radio_band_config *config,
83                            bool withAudio,
84                            sp<IRadio>& radio)
85    {
86        Parcel data, reply;
87        data.writeInterfaceToken(IRadioService::getInterfaceDescriptor());
88        data.writeInt32(handle);
89        data.writeStrongBinder(IInterface::asBinder(client));
90        ALOGV("attach() config %p withAudio %d region %d type %d",
91              config == NULL ? 0 : config, withAudio, config->region, config->band.type);
92        if (config == NULL) {
93            data.writeInt32(0);
94        } else {
95            data.writeInt32(1);
96            data.write(config, sizeof(struct radio_band_config));
97        }
98        data.writeInt32(withAudio ? 1 : 0);
99        status_t status = remote()->transact(ATTACH, data, &reply);
100        if (status != NO_ERROR) {
101            return status;
102        }
103        status = reply.readInt32();
104        if (reply.readInt32() != 0) {
105            radio = interface_cast<IRadio>(reply.readStrongBinder());
106        }
107        return status;
108    }
109};
110
111IMPLEMENT_META_INTERFACE(RadioService, "android.hardware.IRadioService");
112
113// ----------------------------------------------------------------------
114
115status_t BnRadioService::onTransact(
116    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
117{
118    switch(code) {
119        case LIST_MODULES: {
120            CHECK_INTERFACE(IRadioService, data, reply);
121            unsigned int numModulesReq = data.readInt32();
122            if (numModulesReq > MAX_ITEMS_PER_LIST) {
123                numModulesReq = MAX_ITEMS_PER_LIST;
124            }
125            unsigned int numModules = numModulesReq;
126            struct radio_properties *properties =
127                    (struct radio_properties *)calloc(numModulesReq,
128                                                      sizeof(struct radio_properties));
129            if (properties == NULL) {
130                reply->writeInt32(NO_MEMORY);
131                reply->writeInt32(0);
132                return NO_ERROR;
133            }
134
135            status_t status = listModules(properties, &numModules);
136            reply->writeInt32(status);
137            reply->writeInt32(numModules);
138            ALOGV("LIST_MODULES status %d got numModules %d", status, numModules);
139
140            if (status == NO_ERROR) {
141                if (numModulesReq > numModules) {
142                    numModulesReq = numModules;
143                }
144                reply->write(properties,
145                             numModulesReq * sizeof(struct radio_properties));
146            }
147            free(properties);
148            return NO_ERROR;
149        } break;
150
151        case ATTACH: {
152            CHECK_INTERFACE(IRadioService, data, reply);
153            radio_handle_t handle = data.readInt32();
154            sp<IRadioClient> client =
155                    interface_cast<IRadioClient>(data.readStrongBinder());
156            struct radio_band_config config;
157            struct radio_band_config *configPtr = NULL;
158            if (data.readInt32() != 0) {
159                data.read(&config, sizeof(struct radio_band_config));
160                configPtr = &config;
161            }
162            bool withAudio = data.readInt32() != 0;
163            ALOGV("ATTACH configPtr %p withAudio %d", configPtr, withAudio);
164            sp<IRadio> radio;
165            status_t status = attach(handle, client, configPtr, withAudio, radio);
166            reply->writeInt32(status);
167            if (radio != 0) {
168                reply->writeInt32(1);
169                reply->writeStrongBinder(IInterface::asBinder(radio));
170            } else {
171                reply->writeInt32(0);
172            }
173            return NO_ERROR;
174        } break;
175        default:
176            return BBinder::onTransact(code, data, reply, flags);
177    }
178}
179
180// ----------------------------------------------------------------------------
181
182}; // namespace android
183