Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (C) 2015 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 
     17 #define LOG_TAG "radio_metadata"
     18 /*#define LOG_NDEBUG 0*/
     19 
     20 #include <errno.h>
     21 #include <limits.h>
     22 #include <stdlib.h>
     23 #include <string.h>
     24 
     25 #include <log/log.h>
     26 
     27 #include <system/radio.h>
     28 #include <system/radio_metadata.h>
     29 #include "radio_metadata_hidden.h"
     30 
     31 const radio_metadata_type_t metadata_key_type_table[] =
     32 {
     33     RADIO_METADATA_TYPE_INT,
     34     RADIO_METADATA_TYPE_TEXT,
     35     RADIO_METADATA_TYPE_INT,
     36     RADIO_METADATA_TYPE_INT,
     37     RADIO_METADATA_TYPE_TEXT,
     38     RADIO_METADATA_TYPE_TEXT,
     39     RADIO_METADATA_TYPE_TEXT,
     40     RADIO_METADATA_TYPE_TEXT,
     41     RADIO_METADATA_TYPE_TEXT,
     42     RADIO_METADATA_TYPE_RAW,
     43     RADIO_METADATA_TYPE_RAW,
     44     RADIO_METADATA_TYPE_CLOCK,
     45 };
     46 
     47 /**
     48  * private functions
     49  */
     50 
     51 bool is_valid_metadata_key(const radio_metadata_key_t key)
     52 {
     53     if (key < RADIO_METADATA_KEY_MIN || key > RADIO_METADATA_KEY_MAX) {
     54         return false;
     55     }
     56     return true;
     57 }
     58 
     59 int check_size(radio_metadata_buffer_t **metadata_ptr, const uint32_t size_int)
     60 {
     61     radio_metadata_buffer_t *metadata = *metadata_ptr;
     62     uint32_t index_offset = metadata->size_int - metadata->count - 1;
     63     uint32_t data_offset = *((uint32_t *)metadata + index_offset);
     64     uint32_t req_size_int;
     65     uint32_t new_size_int;
     66 
     67     LOG_ALWAYS_FATAL_IF(metadata->size_int < (metadata->count + 1),
     68                         "%s: invalid size %u", __func__, metadata->size_int);
     69     if (size_int == 0) {
     70         return 0;
     71     }
     72 
     73     req_size_int = data_offset + metadata->count + 1 + 1 + size_int;
     74     /* do not grow buffer if it can accommodate the new entry plus an additional index entry */
     75 
     76     if (req_size_int <= metadata->size_int) {
     77         return 0;
     78     }
     79 
     80     if (req_size_int > RADIO_METADATA_MAX_SIZE || metadata->size_int >= RADIO_METADATA_MAX_SIZE) {
     81         return -ENOMEM;
     82     }
     83     /* grow meta data buffer by a factor of 2 until new data fits */
     84     new_size_int = metadata->size_int;
     85     while (new_size_int < req_size_int)
     86         new_size_int *= 2;
     87 
     88     ALOGV("%s growing from %u to %u", __func__, metadata->size_int, new_size_int);
     89     metadata = realloc(metadata, new_size_int * sizeof(uint32_t));
     90     /* move index table */
     91     memmove((uint32_t *)metadata + new_size_int - (metadata->count + 1),
     92             (uint32_t *)metadata + metadata->size_int - (metadata->count + 1),
     93             (metadata->count + 1) * sizeof(uint32_t));
     94     metadata->size_int = new_size_int;
     95 
     96     *metadata_ptr = metadata;
     97     return 0;
     98 }
     99 
    100 /* checks on size and key validity are done before calling this function */
    101 int add_metadata(radio_metadata_buffer_t **metadata_ptr,
    102                  const radio_metadata_key_t key,
    103                  const radio_metadata_type_t type,
    104                  const void *value,
    105                  const size_t size)
    106 {
    107     uint32_t entry_size_int;
    108     int ret;
    109     radio_metadata_entry_t *entry;
    110     uint32_t index_offset;
    111     uint32_t data_offset;
    112     radio_metadata_buffer_t *metadata = *metadata_ptr;
    113 
    114     entry_size_int = (uint32_t)(size + sizeof(radio_metadata_entry_t));
    115     entry_size_int = (entry_size_int + sizeof(uint32_t) - 1) / sizeof(uint32_t);
    116 
    117     ret = check_size(metadata_ptr, entry_size_int);
    118     if (ret < 0) {
    119         return ret;
    120     }
    121     metadata = *metadata_ptr;
    122     index_offset = metadata->size_int - metadata->count - 1;
    123     data_offset = *((uint32_t *)metadata + index_offset);
    124 
    125     entry = (radio_metadata_entry_t *)((uint32_t *)metadata + data_offset);
    126     entry->key = key;
    127     entry->type = type;
    128     entry->size = (uint32_t)size;
    129     memcpy(entry->data, value, size);
    130 
    131     data_offset += entry_size_int;
    132     *((uint32_t *)metadata + index_offset -1) = data_offset;
    133     metadata->count++;
    134 
    135     return 0;
    136 }
    137 
    138 radio_metadata_entry_t *get_entry_at_index(
    139                                     const radio_metadata_buffer_t *metadata,
    140                                     const unsigned index,
    141                                     bool check)
    142 {
    143     uint32_t index_offset = metadata->size_int - index - 1;
    144     uint32_t data_offset = *((uint32_t *)metadata + index_offset);
    145 
    146     LOG_ALWAYS_FATAL_IF(metadata->size_int < (index + 1),
    147                         "%s: invalid size %u", __func__, metadata->size_int);
    148     if (check) {
    149         if (index >= metadata->count) {
    150             return NULL;
    151         }
    152         uint32_t min_offset;
    153         uint32_t max_offset;
    154         uint32_t min_entry_size_int;
    155         min_offset = (sizeof(radio_metadata_buffer_t) + sizeof(uint32_t) - 1) /
    156                         sizeof(uint32_t);
    157         if (data_offset < min_offset) {
    158             return NULL;
    159         }
    160         min_entry_size_int = 1 + sizeof(radio_metadata_entry_t);
    161         min_entry_size_int = (min_entry_size_int + sizeof(uint32_t) - 1) / sizeof(uint32_t);
    162 
    163         LOG_ALWAYS_FATAL_IF(metadata->size_int < (metadata->count + 1),
    164                             "%s: invalid size %u vs count %u", __func__,
    165                             metadata->size_int, metadata->count);
    166 
    167         max_offset = metadata->size_int - metadata->count - 1 - min_entry_size_int;
    168         if (data_offset > max_offset) {
    169             return NULL;
    170         }
    171     }
    172     return (radio_metadata_entry_t *)((uint32_t *)metadata + data_offset);
    173 }
    174 
    175 /**
    176  * metadata API functions
    177  */
    178 
    179 radio_metadata_type_t radio_metadata_type_of_key(const radio_metadata_key_t key)
    180 {
    181     if (!is_valid_metadata_key(key)) {
    182         return RADIO_METADATA_TYPE_INVALID;
    183     }
    184     return metadata_key_type_table[key - RADIO_METADATA_KEY_MIN];
    185 }
    186 
    187 int radio_metadata_allocate(radio_metadata_t **metadata,
    188                             const uint32_t channel,
    189                             const uint32_t sub_channel)
    190 {
    191     radio_metadata_buffer_t *metadata_buf =
    192             (radio_metadata_buffer_t *)calloc(RADIO_METADATA_DEFAULT_SIZE, sizeof(uint32_t));
    193     if (metadata_buf == NULL) {
    194         return -ENOMEM;
    195     }
    196 
    197     metadata_buf->channel = channel;
    198     metadata_buf->sub_channel = sub_channel;
    199     metadata_buf->size_int = RADIO_METADATA_DEFAULT_SIZE;
    200     *((uint32_t *)metadata_buf + RADIO_METADATA_DEFAULT_SIZE - 1) =
    201             (sizeof(radio_metadata_buffer_t) + sizeof(uint32_t) - 1) /
    202                 sizeof(uint32_t);
    203     *metadata = (radio_metadata_t *)metadata_buf;
    204     return 0;
    205 }
    206 
    207 void radio_metadata_deallocate(radio_metadata_t *metadata)
    208 {
    209     free(metadata);
    210 }
    211 
    212 int radio_metadata_add_int(radio_metadata_t **metadata,
    213                            const radio_metadata_key_t key,
    214                            const int32_t value)
    215 {
    216     radio_metadata_type_t type = radio_metadata_type_of_key(key);
    217     if (metadata == NULL || *metadata == NULL || type != RADIO_METADATA_TYPE_INT) {
    218         return -EINVAL;
    219     }
    220     return add_metadata((radio_metadata_buffer_t **)metadata,
    221                         key, type, &value, sizeof(int32_t));
    222 }
    223 
    224 int radio_metadata_add_text(radio_metadata_t **metadata,
    225                             const radio_metadata_key_t key,
    226                             const char *value)
    227 {
    228     radio_metadata_type_t type = radio_metadata_type_of_key(key);
    229     if (metadata == NULL || *metadata == NULL || type != RADIO_METADATA_TYPE_TEXT ||
    230             value == NULL || strlen(value) >= RADIO_METADATA_TEXT_LEN_MAX) {
    231         return -EINVAL;
    232     }
    233     return add_metadata((radio_metadata_buffer_t **)metadata, key, type, value, strlen(value) + 1);
    234 }
    235 
    236 int radio_metadata_add_raw(radio_metadata_t **metadata,
    237                            const radio_metadata_key_t key,
    238                            const unsigned char *value,
    239                            const size_t size)
    240 {
    241     radio_metadata_type_t type = radio_metadata_type_of_key(key);
    242     if (metadata == NULL || *metadata == NULL || type != RADIO_METADATA_TYPE_RAW || value == NULL) {
    243         return -EINVAL;
    244     }
    245     return add_metadata((radio_metadata_buffer_t **)metadata, key, type, value, size);
    246 }
    247 
    248 int radio_metadata_add_clock(radio_metadata_t **metadata,
    249                              const radio_metadata_key_t key,
    250                              const radio_metadata_clock_t *clock) {
    251     radio_metadata_type_t type = radio_metadata_type_of_key(key);
    252     if (metadata == NULL || *metadata == NULL || type != RADIO_METADATA_TYPE_CLOCK ||
    253         clock == NULL || clock->timezone_offset_in_minutes < (-12 * 60) ||
    254         clock->timezone_offset_in_minutes > (14 * 60)) {
    255         return -EINVAL;
    256     }
    257     return add_metadata(
    258         (radio_metadata_buffer_t **)metadata, key, type, clock, sizeof(radio_metadata_clock_t));
    259 }
    260 
    261 int radio_metadata_add_metadata(radio_metadata_t **dst_metadata,
    262                            radio_metadata_t *src_metadata)
    263 {
    264     radio_metadata_buffer_t *src_metadata_buf = (radio_metadata_buffer_t *)src_metadata;
    265     radio_metadata_buffer_t *dst_metadata_buf;
    266     int status;
    267     uint32_t index;
    268 
    269     if (dst_metadata == NULL || src_metadata == NULL) {
    270         return -EINVAL;
    271     }
    272     if (*dst_metadata == NULL) {
    273         status = radio_metadata_allocate(dst_metadata, src_metadata_buf->channel,
    274                                 src_metadata_buf->sub_channel);
    275         if (status != 0) {
    276             return status;
    277         }
    278     }
    279 
    280     dst_metadata_buf = (radio_metadata_buffer_t *)*dst_metadata;
    281     dst_metadata_buf->channel = src_metadata_buf->channel;
    282     dst_metadata_buf->sub_channel = src_metadata_buf->sub_channel;
    283 
    284     for (index = 0; index < src_metadata_buf->count; index++) {
    285         radio_metadata_key_t key;
    286         radio_metadata_type_t type;
    287         void *value;
    288         size_t size;
    289         status = radio_metadata_get_at_index(src_metadata, index, &key, &type, &value, &size);
    290         if (status != 0)
    291             continue;
    292         status = add_metadata((radio_metadata_buffer_t **)dst_metadata, key, type, value, size);
    293         if (status != 0)
    294             break;
    295     }
    296     return status;
    297 }
    298 
    299 int radio_metadata_check(const radio_metadata_t *metadata)
    300 {
    301     radio_metadata_buffer_t *metadata_buf =
    302             (radio_metadata_buffer_t *)metadata;
    303     uint32_t count;
    304     uint32_t min_entry_size_int;
    305 
    306     if (metadata_buf == NULL) {
    307         return -EINVAL;
    308     }
    309 
    310     if (metadata_buf->size_int > RADIO_METADATA_MAX_SIZE) {
    311         return -EINVAL;
    312     }
    313 
    314     /* sanity check on entry count versus buffer size */
    315     min_entry_size_int = 1 + sizeof(radio_metadata_entry_t);
    316     min_entry_size_int = (min_entry_size_int + sizeof(uint32_t) - 1) /
    317                                 sizeof(uint32_t);
    318     if ((metadata_buf->count * min_entry_size_int + metadata_buf->count + 1 +
    319             (sizeof(radio_metadata_buffer_t) + sizeof(uint32_t) - 1) / sizeof(uint32_t)) >
    320                     metadata_buf->size_int) {
    321         return -EINVAL;
    322     }
    323 
    324     /* sanity check on each entry */
    325     for (count = 0; count < metadata_buf->count; count++) {
    326         radio_metadata_entry_t *entry = get_entry_at_index(metadata_buf, count, true);
    327         radio_metadata_entry_t *next_entry;
    328         if (entry == NULL) {
    329             return -EINVAL;
    330         }
    331         if (!is_valid_metadata_key(entry->key)) {
    332             return -EINVAL;
    333         }
    334         if (entry->type != radio_metadata_type_of_key(entry->key)) {
    335             return -EINVAL;
    336         }
    337 
    338         /* do not request check because next entry can be the free slot */
    339         next_entry = get_entry_at_index(metadata_buf, count + 1, false);
    340         if ((char *)entry->data + entry->size > (char *)next_entry) {
    341             return -EINVAL;
    342         }
    343     }
    344 
    345     return 0;
    346 }
    347 
    348 size_t radio_metadata_get_size(const radio_metadata_t *metadata)
    349 {
    350     radio_metadata_buffer_t *metadata_buf =
    351             (radio_metadata_buffer_t *)metadata;
    352 
    353     if (metadata_buf == NULL) {
    354         return 0;
    355     }
    356     return metadata_buf->size_int * sizeof(uint32_t);
    357 }
    358 
    359 int radio_metadata_get_count(const radio_metadata_t *metadata)
    360 {
    361     radio_metadata_buffer_t *metadata_buf =
    362             (radio_metadata_buffer_t *)metadata;
    363 
    364     if (metadata_buf == NULL) {
    365         return -EINVAL;
    366     }
    367     return (int)metadata_buf->count;
    368 }
    369 
    370 int radio_metadata_get_at_index(const radio_metadata_t *metadata,
    371                                 const uint32_t index,
    372                                 radio_metadata_key_t *key,
    373                                 radio_metadata_type_t *type,
    374                                 void **value,
    375                                 size_t *size)
    376 {
    377     radio_metadata_entry_t *entry;
    378     radio_metadata_buffer_t *metadata_buf =
    379             (radio_metadata_buffer_t *)metadata;
    380 
    381     if (metadata_buf == NULL || key == NULL || type == NULL ||
    382             value == NULL || size == NULL) {
    383         return -EINVAL;
    384     }
    385     if (index >= metadata_buf->count) {
    386         return -EINVAL;
    387     }
    388 
    389     entry = get_entry_at_index(metadata_buf, index, false);
    390     *key = entry->key;
    391     *type = entry->type;
    392     *value = (void *)entry->data;
    393     *size = (size_t)entry->size;
    394 
    395     return 0;
    396 }
    397 
    398 int radio_metadata_get_from_key(const radio_metadata_t *metadata,
    399                                 const radio_metadata_key_t key,
    400                                 radio_metadata_type_t *type,
    401                                 void **value,
    402                                 size_t *size)
    403 {
    404     uint32_t count;
    405     radio_metadata_entry_t *entry = NULL;
    406     radio_metadata_buffer_t *metadata_buf =
    407             (radio_metadata_buffer_t *)metadata;
    408 
    409     if (metadata_buf == NULL || type == NULL || value == NULL || size == NULL) {
    410         return -EINVAL;
    411     }
    412     if (!is_valid_metadata_key(key)) {
    413         return -EINVAL;
    414     }
    415 
    416     for (count = 0; count < metadata_buf->count; entry = NULL, count++) {
    417         entry = get_entry_at_index(metadata_buf, count, false);
    418         if (entry->key == key) {
    419             break;
    420         }
    421     }
    422     if (entry == NULL) {
    423         return -ENOENT;
    424     }
    425     *type = entry->type;
    426     *value = (void *)entry->data;
    427     *size = (size_t)entry->size;
    428     return 0;
    429 }
    430 
    431 int radio_metadata_get_channel(radio_metadata_t *metadata,
    432                                uint32_t *channel,
    433                                uint32_t *sub_channel)
    434 {
    435     radio_metadata_buffer_t *metadata_buf =
    436             (radio_metadata_buffer_t *)metadata;
    437 
    438     if (metadata_buf == NULL || channel == NULL || sub_channel == NULL) {
    439         return -EINVAL;
    440     }
    441     *channel = metadata_buf->channel;
    442     *sub_channel = metadata_buf->sub_channel;
    443     return 0;
    444 }
    445