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