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 29const 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 48bool 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 56int 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 */ 96int 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 132radio_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 166radio_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 174int 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 194void radio_metadata_deallocate(radio_metadata_t *metadata) 195{ 196 free(metadata); 197} 198 199int 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 211int 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 223int 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 235int 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 273int 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 322size_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 333int 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 344int 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 374int 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