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
diff --git a/radio/IRadio.cpp b/radio/IRadio.cpp
index 0881a91..ebf3859 100644
--- a/radio/IRadio.cpp
+++ b/radio/IRadio.cpp
@@ -112,7 +112,7 @@
         if (status == NO_ERROR) {
             status = (status_t)reply.readInt32();
             if (status == NO_ERROR) {
-                int muteread = reply.readInt32();
+                int32_t muteread = reply.readInt32();
                 *mute = muteread != 0;
             }
         }
@@ -145,12 +145,12 @@
         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;
         data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
-        data.writeInt32(channel);
-        data.writeInt32(subChannel);
+        data.writeUint32(channel);
+        data.writeUint32(subChannel);
         status_t status = remote()->transact(TUNE, data, &reply);
         if (status == NO_ERROR) {
             status = (status_t)reply.readInt32();
@@ -177,27 +177,29 @@
         }
         radio_metadata_t *metadata = info->metadata;
         data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
+        if (metadata != NULL) {
+            data.writeUint32(1);
+        } else {
+            data.writeUint32(0);
+        }
         status_t status = remote()->transact(GET_PROGRAM_INFORMATION, data, &reply);
         if (status == NO_ERROR) {
             status = (status_t)reply.readInt32();
             if (status == NO_ERROR) {
                 reply.read(info, sizeof(struct radio_program_info));
+                // restore local metadata pointer
                 info->metadata = metadata;
-                if (metadata == NULL) {
-                    return status;
+
+                uint32_t metatataSize = reply.readUint32();
+                if ((metadata != NULL) && (metatataSize != 0)) {
+                    radio_metadata_t *newMetadata = (radio_metadata_t *)malloc(metatataSize);
+                    if (newMetadata == NULL) {
+                        return NO_MEMORY;
+                    }
+                    reply.read(newMetadata, metatataSize);
+                    status = radio_metadata_add_metadata(&info->metadata, newMetadata);
+                    free(newMetadata);
                 }
-                size_t size = (size_t)reply.readInt32();
-                if (size == 0) {
-                    return status;
-                }
-                metadata =
-                    (radio_metadata_t *)calloc(size / sizeof(unsigned int), sizeof(unsigned int));
-                if (metadata == NULL) {
-                    return NO_MEMORY;
-                }
-                reply.read(metadata, size);
-                status = radio_metadata_add_metadata(&info->metadata, metadata);
-                free(metadata);
             }
         }
         return status;
@@ -288,8 +290,8 @@
         }
         case TUNE: {
             CHECK_INTERFACE(IRadio, data, reply);
-            unsigned int channel = (unsigned int)data.readInt32();
-            unsigned int subChannel = (unsigned int)data.readInt32();
+            uint32_t channel = data.readUint32();
+            uint32_t subChannel = data.readUint32();
             status_t status = tune(channel, subChannel);
             reply->writeInt32(status);
             return NO_ERROR;
@@ -303,22 +305,27 @@
         case GET_PROGRAM_INFORMATION: {
             CHECK_INTERFACE(IRadio, data, reply);
             struct radio_program_info info;
-
-            status_t status = radio_metadata_allocate(&info.metadata, 0, 0);
-            if (status != NO_ERROR) {
-                return status;
+            status_t status;
+            // query metadata only if requested by remote side
+            if (data.readUint32() == 1) {
+                status = radio_metadata_allocate(&info.metadata, 0, 0);
+                if (status != NO_ERROR) {
+                    return status;
+                }
+            } else {
+                info.metadata = NULL;
             }
             status = getProgramInformation(&info);
+
             reply->writeInt32(status);
             if (status == NO_ERROR) {
                 reply->write(&info, sizeof(struct radio_program_info));
-                int count = radio_metadata_get_count(info.metadata);
-                if (count > 0) {
+                if ((info.metadata != NULL) && (radio_metadata_get_count(info.metadata) > 0)) {
                     size_t size = radio_metadata_get_size(info.metadata);
-                    reply->writeInt32(size);
+                    reply->writeUint32((uint32_t)size);
                     reply->write(info.metadata, size);
                 } else {
-                    reply->writeInt32(0);
+                    reply->writeUint32(0);
                 }
             }
             radio_metadata_deallocate(info.metadata);
diff --git a/radio/IRadioService.cpp b/radio/IRadioService.cpp
index be7d21e..72e3a61 100644
--- a/radio/IRadioService.cpp
+++ b/radio/IRadioService.cpp
@@ -16,8 +16,7 @@
 */
 
 #define LOG_TAG "BpRadioService"
-//
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
 
 #include <utils/Log.h>
 #include <utils/Errors.h>
@@ -58,12 +57,12 @@
         }
         Parcel data, reply;
         data.writeInterfaceToken(IRadioService::getInterfaceDescriptor());
-        unsigned int numModulesReq = (properties == NULL) ? 0 : *numModules;
+        uint32_t numModulesReq = (properties == NULL) ? 0 : *numModules;
         data.writeInt32(numModulesReq);
         status_t status = remote()->transact(LIST_MODULES, data, &reply);
         if (status == NO_ERROR) {
             status = (status_t)reply.readInt32();
-            *numModules = (unsigned int)reply.readInt32();
+            *numModules = (uint32_t)reply.readInt32();
         }
         ALOGV("listModules() status %d got *numModules %d", status, *numModules);
         if (status == NO_ERROR) {
@@ -120,11 +119,11 @@
     switch(code) {
         case LIST_MODULES: {
             CHECK_INTERFACE(IRadioService, data, reply);
-            unsigned int numModulesReq = data.readInt32();
+            uint32_t numModulesReq = data.readInt32();
             if (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 *)calloc(numModulesReq,
                                                       sizeof(struct radio_properties));
diff --git a/radio/Radio.cpp b/radio/Radio.cpp
index 3c04fb0..fa39589 100644
--- a/radio/Radio.cpp
+++ b/radio/Radio.cpp
@@ -240,20 +240,31 @@
         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();
+    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
     switch (event->type) {
     case RADIO_EVENT_TUNED:
     case RADIO_EVENT_AF_SWITCH:
-        if (event->info.metadata != NULL) {
+        if (metadataSize != 0) {
             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;
     case RADIO_EVENT_METADATA:
-        if (event->metadata != NULL) {
+        if (metadataSize != 0) {
             event->metadata =
-                    (radio_metadata_t *)((char *)event + (size_t)event->metadata);
+                    (radio_metadata_t *)((uint8_t *)event + metadataOffset);
+        } else {
+            event->metadata = 0;
         }
         break;
     default:
diff --git a/services/radio/RadioService.cpp b/services/radio/RadioService.cpp
index 5a3f750..e079552 100644
--- a/services/radio/RadioService.cpp
+++ b/services/radio/RadioService.cpp
@@ -305,32 +305,40 @@
 {
     sp<IMemory> eventMemory;
 
-    size_t headerSize =
-            (sizeof(struct radio_event) + sizeof(unsigned int) - 1) /sizeof(unsigned int);
-    size_t metadataSize = 0;
+    // 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
+    uint32_t metadataOffset = sizeof(struct radio_event) + sizeof(uint32_t);
+    uint32_t metadataSize = 0;
+
     switch (halEvent->type) {
     case RADIO_EVENT_TUNED:
     case RADIO_EVENT_AF_SWITCH:
         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;
     case RADIO_EVENT_METADATA:
         if (radio_metadata_check(halEvent->metadata) != 0) {
             return eventMemory;
         }
-        metadataSize = radio_metadata_get_size(halEvent->metadata);
+        metadataSize = (uint32_t)radio_metadata_get_size(halEvent->metadata);
         break;
     default:
         break;
     }
-    size_t size = headerSize + metadataSize;
-    eventMemory = mMemoryDealer->allocate(size);
+
+    eventMemory = mMemoryDealer->allocate(metadataOffset + metadataSize);
     if (eventMemory == 0 || eventMemory->pointer() == NULL) {
         eventMemory.clear();
         return eventMemory;
     }
+
     struct radio_event *event = (struct radio_event *)eventMemory->pointer();
+
+    *(uint32_t *)((uint8_t *)event + metadataOffset - sizeof(uint32_t)) = metadataSize;
+
     event->type = halEvent->type;
     event->status = halEvent->status;
 
@@ -342,10 +350,7 @@
     case RADIO_EVENT_AF_SWITCH:
         event->info = halEvent->info;
         if (metadataSize != 0) {
-            memcpy((char *)event + headerSize, 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;
+            memcpy((uint8_t *)event + metadataOffset, halEvent->info.metadata, metadataSize);
         }
         break;
     case RADIO_EVENT_TA:
@@ -355,10 +360,9 @@
         event->on = halEvent->on;
         break;
     case RADIO_EVENT_METADATA:
-        memcpy((char *)event + headerSize, halEvent->metadata, metadataSize);
-        // replace meta data pointer by offset while in shared memory so that receiving side
-        // can restore the pointer in destination process.
-        event->metadata = (radio_metadata_t *)headerSize;
+        if (metadataSize != 0) {
+            memcpy((uint8_t *)event + metadataOffset, halEvent->metadata, metadataSize);
+        }
         break;
     case RADIO_EVENT_HW_FAILURE:
     default:
@@ -853,6 +857,7 @@
     } else {
         status = INVALID_OPERATION;
     }
+
     return status;
 }