Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit aebf5fbc authored by Eric Laurent's avatar Eric Laurent
Browse files

radio: fix 64 bit process compatibility

Fix binder call implementations and shared memory layout to make sure
that structures containig a pointer to metadata buffer are passed
correctly between 32 bit and 64 bit processes.

Change-Id: Ibecf260555225e0764411f62b60831511cb68278
parent fa92ed03
Loading
Loading
Loading
Loading
+35 −28
Original line number Original line Diff line number Diff line
@@ -112,7 +112,7 @@ public:
        if (status == NO_ERROR) {
        if (status == NO_ERROR) {
            status = (status_t)reply.readInt32();
            status = (status_t)reply.readInt32();
            if (status == NO_ERROR) {
            if (status == NO_ERROR) {
                int muteread = reply.readInt32();
                int32_t muteread = reply.readInt32();
                *mute = muteread != 0;
                *mute = muteread != 0;
            }
            }
        }
        }
@@ -145,12 +145,12 @@ public:
        return status;
        return status;
    }
    }


    virtual status_t tune(unsigned int channel, unsigned int subChannel)
    virtual status_t tune(uint32_t channel, uint32_t subChannel)
    {
    {
        Parcel data, reply;
        Parcel data, reply;
        data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
        data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
        data.writeInt32(channel);
        data.writeUint32(channel);
        data.writeInt32(subChannel);
        data.writeUint32(subChannel);
        status_t status = remote()->transact(TUNE, data, &reply);
        status_t status = remote()->transact(TUNE, data, &reply);
        if (status == NO_ERROR) {
        if (status == NO_ERROR) {
            status = (status_t)reply.readInt32();
            status = (status_t)reply.readInt32();
@@ -177,27 +177,29 @@ public:
        }
        }
        radio_metadata_t *metadata = info->metadata;
        radio_metadata_t *metadata = info->metadata;
        data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
        data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
        if (metadata != NULL) {
            data.writeUint32(1);
        } else {
            data.writeUint32(0);
        }
        status_t status = remote()->transact(GET_PROGRAM_INFORMATION, data, &reply);
        status_t status = remote()->transact(GET_PROGRAM_INFORMATION, data, &reply);
        if (status == NO_ERROR) {
        if (status == NO_ERROR) {
            status = (status_t)reply.readInt32();
            status = (status_t)reply.readInt32();
            if (status == NO_ERROR) {
            if (status == NO_ERROR) {
                reply.read(info, sizeof(struct radio_program_info));
                reply.read(info, sizeof(struct radio_program_info));
                // restore local metadata pointer
                info->metadata = metadata;
                info->metadata = metadata;
                if (metadata == NULL) {

                    return status;
                uint32_t metatataSize = reply.readUint32();
                }
                if ((metadata != NULL) && (metatataSize != 0)) {
                size_t size = (size_t)reply.readInt32();
                    radio_metadata_t *newMetadata = (radio_metadata_t *)malloc(metatataSize);
                if (size == 0) {
                    if (newMetadata == NULL) {
                    return status;
                }
                metadata =
                    (radio_metadata_t *)calloc(size / sizeof(unsigned int), sizeof(unsigned int));
                if (metadata == NULL) {
                        return NO_MEMORY;
                        return NO_MEMORY;
                    }
                    }
                reply.read(metadata, size);
                    reply.read(newMetadata, metatataSize);
                status = radio_metadata_add_metadata(&info->metadata, metadata);
                    status = radio_metadata_add_metadata(&info->metadata, newMetadata);
                free(metadata);
                    free(newMetadata);
                }
            }
            }
        }
        }
        return status;
        return status;
@@ -288,8 +290,8 @@ status_t BnRadio::onTransact(
        }
        }
        case TUNE: {
        case TUNE: {
            CHECK_INTERFACE(IRadio, data, reply);
            CHECK_INTERFACE(IRadio, data, reply);
            unsigned int channel = (unsigned int)data.readInt32();
            uint32_t channel = data.readUint32();
            unsigned int subChannel = (unsigned int)data.readInt32();
            uint32_t subChannel = data.readUint32();
            status_t status = tune(channel, subChannel);
            status_t status = tune(channel, subChannel);
            reply->writeInt32(status);
            reply->writeInt32(status);
            return NO_ERROR;
            return NO_ERROR;
@@ -303,22 +305,27 @@ status_t BnRadio::onTransact(
        case GET_PROGRAM_INFORMATION: {
        case GET_PROGRAM_INFORMATION: {
            CHECK_INTERFACE(IRadio, data, reply);
            CHECK_INTERFACE(IRadio, data, reply);
            struct radio_program_info info;
            struct radio_program_info info;

            status_t status;
            status_t status = radio_metadata_allocate(&info.metadata, 0, 0);
            // query metadata only if requested by remote side
            if (data.readUint32() == 1) {
                status = radio_metadata_allocate(&info.metadata, 0, 0);
                if (status != NO_ERROR) {
                if (status != NO_ERROR) {
                    return status;
                    return status;
                }
                }
            } else {
                info.metadata = NULL;
            }
            status = getProgramInformation(&info);
            status = getProgramInformation(&info);

            reply->writeInt32(status);
            reply->writeInt32(status);
            if (status == NO_ERROR) {
            if (status == NO_ERROR) {
                reply->write(&info, sizeof(struct radio_program_info));
                reply->write(&info, sizeof(struct radio_program_info));
                int count = radio_metadata_get_count(info.metadata);
                if ((info.metadata != NULL) && (radio_metadata_get_count(info.metadata) > 0)) {
                if (count > 0) {
                    size_t size = radio_metadata_get_size(info.metadata);
                    size_t size = radio_metadata_get_size(info.metadata);
                    reply->writeInt32(size);
                    reply->writeUint32((uint32_t)size);
                    reply->write(info.metadata, size);
                    reply->write(info.metadata, size);
                } else {
                } else {
                    reply->writeInt32(0);
                    reply->writeUint32(0);
                }
                }
            }
            }
            radio_metadata_deallocate(info.metadata);
            radio_metadata_deallocate(info.metadata);
+5 −6
Original line number Original line Diff line number Diff line
@@ -16,8 +16,7 @@
*/
*/


#define LOG_TAG "BpRadioService"
#define LOG_TAG "BpRadioService"
//
//#define LOG_NDEBUG 0
#define LOG_NDEBUG 0


#include <utils/Log.h>
#include <utils/Log.h>
#include <utils/Errors.h>
#include <utils/Errors.h>
@@ -58,12 +57,12 @@ public:
        }
        }
        Parcel data, reply;
        Parcel data, reply;
        data.writeInterfaceToken(IRadioService::getInterfaceDescriptor());
        data.writeInterfaceToken(IRadioService::getInterfaceDescriptor());
        unsigned int numModulesReq = (properties == NULL) ? 0 : *numModules;
        uint32_t numModulesReq = (properties == NULL) ? 0 : *numModules;
        data.writeInt32(numModulesReq);
        data.writeInt32(numModulesReq);
        status_t status = remote()->transact(LIST_MODULES, data, &reply);
        status_t status = remote()->transact(LIST_MODULES, data, &reply);
        if (status == NO_ERROR) {
        if (status == NO_ERROR) {
            status = (status_t)reply.readInt32();
            status = (status_t)reply.readInt32();
            *numModules = (unsigned int)reply.readInt32();
            *numModules = (uint32_t)reply.readInt32();
        }
        }
        ALOGV("listModules() status %d got *numModules %d", status, *numModules);
        ALOGV("listModules() status %d got *numModules %d", status, *numModules);
        if (status == NO_ERROR) {
        if (status == NO_ERROR) {
@@ -120,11 +119,11 @@ status_t BnRadioService::onTransact(
    switch(code) {
    switch(code) {
        case LIST_MODULES: {
        case LIST_MODULES: {
            CHECK_INTERFACE(IRadioService, data, reply);
            CHECK_INTERFACE(IRadioService, data, reply);
            unsigned int numModulesReq = data.readInt32();
            uint32_t numModulesReq = data.readInt32();
            if (numModulesReq > MAX_ITEMS_PER_LIST) {
            if (numModulesReq > MAX_ITEMS_PER_LIST) {
                numModulesReq = MAX_ITEMS_PER_LIST;
                numModulesReq = MAX_ITEMS_PER_LIST;
            }
            }
            unsigned int numModules = numModulesReq;
            uint32_t numModules = numModulesReq;
            struct radio_properties *properties =
            struct radio_properties *properties =
                    (struct radio_properties *)calloc(numModulesReq,
                    (struct radio_properties *)calloc(numModulesReq,
                                                      sizeof(struct radio_properties));
                                                      sizeof(struct radio_properties));
+15 −4
Original line number Original line Diff line number Diff line
@@ -240,20 +240,31 @@ void Radio::onEvent(const sp<IMemory>& eventMemory)
        return;
        return;
    }
    }


    // The event layout in shared memory is:
    // sizeof(struct radio_event) bytes : the event itself
    // 4 bytes                          : metadata size or 0
    // N bytes                          : metadata if present
    struct radio_event *event = (struct radio_event *)eventMemory->pointer();
    struct radio_event *event = (struct radio_event *)eventMemory->pointer();
    uint32_t metadataOffset = sizeof(struct radio_event) + sizeof(uint32_t);
    uint32_t metadataSize = *(uint32_t *)((uint8_t *)event + metadataOffset - sizeof(uint32_t));

    // restore local metadata pointer from offset
    // restore local metadata pointer from offset
    switch (event->type) {
    switch (event->type) {
    case RADIO_EVENT_TUNED:
    case RADIO_EVENT_TUNED:
    case RADIO_EVENT_AF_SWITCH:
    case RADIO_EVENT_AF_SWITCH:
        if (event->info.metadata != NULL) {
        if (metadataSize != 0) {
            event->info.metadata =
            event->info.metadata =
                    (radio_metadata_t *)((char *)event + (size_t)event->info.metadata);
                    (radio_metadata_t *)((uint8_t *)event + metadataOffset);
        } else {
            event->info.metadata = 0;
        }
        }
        break;
        break;
    case RADIO_EVENT_METADATA:
    case RADIO_EVENT_METADATA:
        if (event->metadata != NULL) {
        if (metadataSize != 0) {
            event->metadata =
            event->metadata =
                    (radio_metadata_t *)((char *)event + (size_t)event->metadata);
                    (radio_metadata_t *)((uint8_t *)event + metadataOffset);
        } else {
            event->metadata = 0;
        }
        }
        break;
        break;
    default:
    default:
+20 −15
Original line number Original line Diff line number Diff line
@@ -305,32 +305,40 @@ sp<IMemory> RadioService::CallbackThread::prepareEvent(radio_hal_event_t *halEve
{
{
    sp<IMemory> eventMemory;
    sp<IMemory> eventMemory;


    size_t headerSize =
    // The event layout in shared memory is:
            (sizeof(struct radio_event) + sizeof(unsigned int) - 1) /sizeof(unsigned int);
    // sizeof(struct radio_event) bytes : the event itself
    size_t metadataSize = 0;
    // 4 bytes                          : metadata size or 0
    // N bytes                          : metadata if present
    uint32_t metadataOffset = sizeof(struct radio_event) + sizeof(uint32_t);
    uint32_t metadataSize = 0;

    switch (halEvent->type) {
    switch (halEvent->type) {
    case RADIO_EVENT_TUNED:
    case RADIO_EVENT_TUNED:
    case RADIO_EVENT_AF_SWITCH:
    case RADIO_EVENT_AF_SWITCH:
        if (radio_metadata_check(halEvent->info.metadata) == 0) {
        if (radio_metadata_check(halEvent->info.metadata) == 0) {
            metadataSize = radio_metadata_get_size(halEvent->info.metadata);
            metadataSize = (uint32_t)radio_metadata_get_size(halEvent->info.metadata);
        }
        }
        break;
        break;
    case RADIO_EVENT_METADATA:
    case RADIO_EVENT_METADATA:
        if (radio_metadata_check(halEvent->metadata) != 0) {
        if (radio_metadata_check(halEvent->metadata) != 0) {
            return eventMemory;
            return eventMemory;
        }
        }
        metadataSize = radio_metadata_get_size(halEvent->metadata);
        metadataSize = (uint32_t)radio_metadata_get_size(halEvent->metadata);
        break;
        break;
    default:
    default:
        break;
        break;
    }
    }
    size_t size = headerSize + metadataSize;

    eventMemory = mMemoryDealer->allocate(size);
    eventMemory = mMemoryDealer->allocate(metadataOffset + metadataSize);
    if (eventMemory == 0 || eventMemory->pointer() == NULL) {
    if (eventMemory == 0 || eventMemory->pointer() == NULL) {
        eventMemory.clear();
        eventMemory.clear();
        return eventMemory;
        return eventMemory;
    }
    }

    struct radio_event *event = (struct radio_event *)eventMemory->pointer();
    struct radio_event *event = (struct radio_event *)eventMemory->pointer();

    *(uint32_t *)((uint8_t *)event + metadataOffset - sizeof(uint32_t)) = metadataSize;

    event->type = halEvent->type;
    event->type = halEvent->type;
    event->status = halEvent->status;
    event->status = halEvent->status;


@@ -342,10 +350,7 @@ sp<IMemory> RadioService::CallbackThread::prepareEvent(radio_hal_event_t *halEve
    case RADIO_EVENT_AF_SWITCH:
    case RADIO_EVENT_AF_SWITCH:
        event->info = halEvent->info;
        event->info = halEvent->info;
        if (metadataSize != 0) {
        if (metadataSize != 0) {
            memcpy((char *)event + headerSize, halEvent->info.metadata, metadataSize);
            memcpy((uint8_t *)event + metadataOffset, halEvent->info.metadata, metadataSize);
            // replace meta data pointer by offset while in shared memory so that receiving side
            // can restore the pointer in destination process.
            event->info.metadata = (radio_metadata_t *)headerSize;
        }
        }
        break;
        break;
    case RADIO_EVENT_TA:
    case RADIO_EVENT_TA:
@@ -355,10 +360,9 @@ sp<IMemory> RadioService::CallbackThread::prepareEvent(radio_hal_event_t *halEve
        event->on = halEvent->on;
        event->on = halEvent->on;
        break;
        break;
    case RADIO_EVENT_METADATA:
    case RADIO_EVENT_METADATA:
        memcpy((char *)event + headerSize, halEvent->metadata, metadataSize);
        if (metadataSize != 0) {
        // replace meta data pointer by offset while in shared memory so that receiving side
            memcpy((uint8_t *)event + metadataOffset, halEvent->metadata, metadataSize);
        // can restore the pointer in destination process.
        }
        event->metadata = (radio_metadata_t *)headerSize;
        break;
        break;
    case RADIO_EVENT_HW_FAILURE:
    case RADIO_EVENT_HW_FAILURE:
    default:
    default:
@@ -853,6 +857,7 @@ status_t RadioService::ModuleClient::getProgramInformation(struct radio_program_
    } else {
    } else {
        status = INVALID_OPERATION;
        status = INVALID_OPERATION;
    }
    }

    return status;
    return status;
}
}