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_TEXT, 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