1 /*
2  * Copyright (C) 2009 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_NDEBUG 0
18 #define LOG_TAG "MetaDataBase"
19 #include <inttypes.h>
20 #include <utils/KeyedVector.h>
21 #include <utils/Log.h>
22 
23 #include <stdlib.h>
24 #include <string.h>
25 
26 #include <mutex>
27 
28 #include <media/stagefright/foundation/ADebug.h>
29 #include <media/stagefright/foundation/AString.h>
30 #include <media/stagefright/foundation/hexdump.h>
31 #include <media/stagefright/MetaDataBase.h>
32 
33 #if defined(__ANDROID__) && !defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
34 #include <binder/Parcel.h>
35 #endif
36 
37 namespace android {
38 
39 struct MetaDataBase::typed_data {
40     typed_data();
41     ~typed_data();
42 
43     typed_data(const MetaDataBase::typed_data &);
44     typed_data &operator=(const MetaDataBase::typed_data &);
45 
46     void clear();
47     void setData(uint32_t type, const void *data, size_t size);
48     void getData(uint32_t *type, const void **data, size_t *size) const;
49     // may include hexdump of binary data if verbose=true
50     String8 asString(bool verbose) const;
51 
52 private:
53     uint32_t mType;
54     size_t mSize;
55 
56     union {
57         void *ext_data;
58         float reservoir;
59     } u;
60 
usesReservoirandroid::MetaDataBase::typed_data61     bool usesReservoir() const {
62         return mSize <= sizeof(u.reservoir);
63     }
64 
65     void *allocateStorage(size_t size);
66     void freeStorage();
67 
storageandroid::MetaDataBase::typed_data68     void *storage() {
69         return usesReservoir() ? &u.reservoir : u.ext_data;
70     }
71 
storageandroid::MetaDataBase::typed_data72     const void *storage() const {
73         return usesReservoir() ? &u.reservoir : u.ext_data;
74     }
75 };
76 
77 struct MetaDataBase::Rect {
78     int32_t mLeft, mTop, mRight, mBottom;
79 };
80 
81 
82 struct MetaDataBase::MetaDataInternal {
83     std::mutex mLock;
84     KeyedVector<uint32_t, MetaDataBase::typed_data> mItems;
85 };
86 
87 
MetaDataBase()88 MetaDataBase::MetaDataBase()
89     : mInternalData(new MetaDataInternal()) {
90 }
91 
MetaDataBase(const MetaDataBase & from)92 MetaDataBase::MetaDataBase(const MetaDataBase &from)
93     : mInternalData(new MetaDataInternal()) {
94     mInternalData->mItems = from.mInternalData->mItems;
95 }
96 
operator =(const MetaDataBase & rhs)97 MetaDataBase& MetaDataBase::operator = (const MetaDataBase &rhs) {
98     this->mInternalData->mItems = rhs.mInternalData->mItems;
99     return *this;
100 }
101 
~MetaDataBase()102 MetaDataBase::~MetaDataBase() {
103     clear();
104     delete mInternalData;
105 }
106 
clear()107 void MetaDataBase::clear() {
108     std::lock_guard<std::mutex> guard(mInternalData->mLock);
109     mInternalData->mItems.clear();
110 }
111 
remove(uint32_t key)112 bool MetaDataBase::remove(uint32_t key) {
113     std::lock_guard<std::mutex> guard(mInternalData->mLock);
114     ssize_t i = mInternalData->mItems.indexOfKey(key);
115 
116     if (i < 0) {
117         return false;
118     }
119 
120     mInternalData->mItems.removeItemsAt(i);
121 
122     return true;
123 }
124 
setCString(uint32_t key,const char * value)125 bool MetaDataBase::setCString(uint32_t key, const char *value) {
126     return setData(key, TYPE_C_STRING, value, strlen(value) + 1);
127 }
128 
setInt32(uint32_t key,int32_t value)129 bool MetaDataBase::setInt32(uint32_t key, int32_t value) {
130     return setData(key, TYPE_INT32, &value, sizeof(value));
131 }
132 
setInt64(uint32_t key,int64_t value)133 bool MetaDataBase::setInt64(uint32_t key, int64_t value) {
134     return setData(key, TYPE_INT64, &value, sizeof(value));
135 }
136 
setFloat(uint32_t key,float value)137 bool MetaDataBase::setFloat(uint32_t key, float value) {
138     return setData(key, TYPE_FLOAT, &value, sizeof(value));
139 }
140 
setPointer(uint32_t key,void * value)141 bool MetaDataBase::setPointer(uint32_t key, void *value) {
142     return setData(key, TYPE_POINTER, &value, sizeof(value));
143 }
144 
setRect(uint32_t key,int32_t left,int32_t top,int32_t right,int32_t bottom)145 bool MetaDataBase::setRect(
146         uint32_t key,
147         int32_t left, int32_t top,
148         int32_t right, int32_t bottom) {
149     Rect r;
150     r.mLeft = left;
151     r.mTop = top;
152     r.mRight = right;
153     r.mBottom = bottom;
154 
155     return setData(key, TYPE_RECT, &r, sizeof(r));
156 }
157 
158 /**
159  * Note that the returned pointer becomes invalid when additional metadata is set.
160  */
findCString(uint32_t key,const char ** value) const161 bool MetaDataBase::findCString(uint32_t key, const char **value) const {
162     uint32_t type;
163     const void *data;
164     size_t size;
165     if (!findData(key, &type, &data, &size) || type != TYPE_C_STRING) {
166         return false;
167     }
168 
169     *value = (const char *)data;
170 
171     return true;
172 }
173 
findInt32(uint32_t key,int32_t * value) const174 bool MetaDataBase::findInt32(uint32_t key, int32_t *value) const {
175     uint32_t type = 0;
176     const void *data;
177     size_t size;
178     if (!findData(key, &type, &data, &size) || type != TYPE_INT32) {
179         return false;
180     }
181 
182     CHECK_EQ(size, sizeof(*value));
183 
184     *value = *(int32_t *)data;
185 
186     return true;
187 }
188 
findInt64(uint32_t key,int64_t * value) const189 bool MetaDataBase::findInt64(uint32_t key, int64_t *value) const {
190     uint32_t type = 0;
191     const void *data;
192     size_t size;
193     if (!findData(key, &type, &data, &size) || type != TYPE_INT64) {
194         return false;
195     }
196 
197     CHECK_EQ(size, sizeof(*value));
198 
199     *value = *(int64_t *)data;
200 
201     return true;
202 }
203 
findFloat(uint32_t key,float * value) const204 bool MetaDataBase::findFloat(uint32_t key, float *value) const {
205     uint32_t type = 0;
206     const void *data;
207     size_t size;
208     if (!findData(key, &type, &data, &size) || type != TYPE_FLOAT) {
209         return false;
210     }
211 
212     CHECK_EQ(size, sizeof(*value));
213 
214     *value = *(float *)data;
215 
216     return true;
217 }
218 
findPointer(uint32_t key,void ** value) const219 bool MetaDataBase::findPointer(uint32_t key, void **value) const {
220     uint32_t type = 0;
221     const void *data;
222     size_t size;
223     if (!findData(key, &type, &data, &size) || type != TYPE_POINTER) {
224         return false;
225     }
226 
227     CHECK_EQ(size, sizeof(*value));
228 
229     *value = *(void **)data;
230 
231     return true;
232 }
233 
findRect(uint32_t key,int32_t * left,int32_t * top,int32_t * right,int32_t * bottom) const234 bool MetaDataBase::findRect(
235         uint32_t key,
236         int32_t *left, int32_t *top,
237         int32_t *right, int32_t *bottom) const {
238     uint32_t type = 0;
239     const void *data;
240     size_t size;
241     if (!findData(key, &type, &data, &size) || type != TYPE_RECT) {
242         return false;
243     }
244 
245     CHECK_EQ(size, sizeof(Rect));
246 
247     const Rect *r = (const Rect *)data;
248     *left = r->mLeft;
249     *top = r->mTop;
250     *right = r->mRight;
251     *bottom = r->mBottom;
252 
253     return true;
254 }
255 
setData(uint32_t key,uint32_t type,const void * data,size_t size)256 bool MetaDataBase::setData(
257         uint32_t key, uint32_t type, const void *data, size_t size) {
258     bool overwrote_existing = true;
259 
260     std::lock_guard<std::mutex> guard(mInternalData->mLock);
261     ssize_t i = mInternalData->mItems.indexOfKey(key);
262     if (i < 0) {
263         typed_data item;
264         i = mInternalData->mItems.add(key, item);
265 
266         overwrote_existing = false;
267     }
268 
269     typed_data &item = mInternalData->mItems.editValueAt(i);
270 
271     item.setData(type, data, size);
272 
273     return overwrote_existing;
274 }
275 
findData(uint32_t key,uint32_t * type,const void ** data,size_t * size) const276 bool MetaDataBase::findData(uint32_t key, uint32_t *type,
277                         const void **data, size_t *size) const {
278     std::lock_guard<std::mutex> guard(mInternalData->mLock);
279     ssize_t i = mInternalData->mItems.indexOfKey(key);
280 
281     if (i < 0) {
282         return false;
283     }
284 
285     const typed_data &item = mInternalData->mItems.valueAt(i);
286 
287     item.getData(type, data, size);
288 
289     return true;
290 }
291 
hasData(uint32_t key) const292 bool MetaDataBase::hasData(uint32_t key) const {
293     std::lock_guard<std::mutex> guard(mInternalData->mLock);
294     ssize_t i = mInternalData->mItems.indexOfKey(key);
295 
296     if (i < 0) {
297         return false;
298     }
299 
300     return true;
301 }
302 
typed_data()303 MetaDataBase::typed_data::typed_data()
304     : mType(0),
305       mSize(0) {
306 }
307 
~typed_data()308 MetaDataBase::typed_data::~typed_data() {
309     clear();
310 }
311 
typed_data(const typed_data & from)312 MetaDataBase::typed_data::typed_data(const typed_data &from)
313     : mType(from.mType),
314       mSize(0) {
315 
316     void *dst = allocateStorage(from.mSize);
317     if (dst) {
318         memcpy(dst, from.storage(), mSize);
319     }
320 }
321 
operator =(const MetaDataBase::typed_data & from)322 MetaDataBase::typed_data &MetaDataBase::typed_data::operator=(
323         const MetaDataBase::typed_data &from) {
324     if (this != &from) {
325         clear();
326         mType = from.mType;
327         void *dst = allocateStorage(from.mSize);
328         if (dst) {
329             memcpy(dst, from.storage(), mSize);
330         }
331     }
332 
333     return *this;
334 }
335 
clear()336 void MetaDataBase::typed_data::clear() {
337     freeStorage();
338 
339     mType = 0;
340 }
341 
setData(uint32_t type,const void * data,size_t size)342 void MetaDataBase::typed_data::setData(
343         uint32_t type, const void *data, size_t size) {
344     clear();
345 
346     mType = type;
347 
348     void *dst = allocateStorage(size);
349     if (dst) {
350         memcpy(dst, data, size);
351     }
352 }
353 
getData(uint32_t * type,const void ** data,size_t * size) const354 void MetaDataBase::typed_data::getData(
355         uint32_t *type, const void **data, size_t *size) const {
356     *type = mType;
357     *size = mSize;
358     *data = storage();
359 }
360 
allocateStorage(size_t size)361 void *MetaDataBase::typed_data::allocateStorage(size_t size) {
362     mSize = size;
363 
364     if (usesReservoir()) {
365         return &u.reservoir;
366     }
367 
368     u.ext_data = malloc(mSize);
369     if (u.ext_data == NULL) {
370         ALOGE("Couldn't allocate %zu bytes for item", size);
371         mSize = 0;
372     }
373     return u.ext_data;
374 }
375 
freeStorage()376 void MetaDataBase::typed_data::freeStorage() {
377     if (!usesReservoir()) {
378         if (u.ext_data) {
379             free(u.ext_data);
380             u.ext_data = NULL;
381         }
382     }
383 
384     mSize = 0;
385 }
386 
asString(bool verbose) const387 String8 MetaDataBase::typed_data::asString(bool verbose) const {
388     String8 out;
389     const void *data = storage();
390     switch(mType) {
391         case TYPE_NONE:
392             out = String8::format("no type, size %zu)", mSize);
393             break;
394         case TYPE_C_STRING:
395             out = String8::format("(char*) %s", (const char *)data);
396             break;
397         case TYPE_INT32:
398             out = String8::format("(int32_t) %d", *(int32_t *)data);
399             break;
400         case TYPE_INT64:
401             out = String8::format("(int64_t) %" PRId64, *(int64_t *)data);
402             break;
403         case TYPE_FLOAT:
404             out = String8::format("(float) %f", *(float *)data);
405             break;
406         case TYPE_POINTER:
407             out = String8::format("(void*) %p", *(void **)data);
408             break;
409         case TYPE_RECT:
410         {
411             const Rect *r = (const Rect *)data;
412             out = String8::format("Rect(%d, %d, %d, %d)",
413                                   r->mLeft, r->mTop, r->mRight, r->mBottom);
414             break;
415         }
416 
417         default:
418             out = String8::format("(unknown type %d, size %zu)", mType, mSize);
419             if (verbose && mSize <= 48) { // if it's less than three lines of hex data, dump it
420                 AString foo;
421                 hexdump(data, mSize, 0, &foo);
422                 out.append("\n");
423                 out.append(foo.c_str());
424             }
425             break;
426     }
427     return out;
428 }
429 
MakeFourCCString(uint32_t x,char * s)430 static void MakeFourCCString(uint32_t x, char *s) {
431     s[0] = x >> 24;
432     s[1] = (x >> 16) & 0xff;
433     s[2] = (x >> 8) & 0xff;
434     s[3] = x & 0xff;
435     s[4] = '\0';
436 }
437 
toString() const438 String8 MetaDataBase::toString() const {
439     String8 s;
440     std::lock_guard<std::mutex> guard(mInternalData->mLock);
441     for (int i = mInternalData->mItems.size(); --i >= 0;) {
442         int32_t key = mInternalData->mItems.keyAt(i);
443         char cc[5];
444         MakeFourCCString(key, cc);
445         const typed_data &item = mInternalData->mItems.valueAt(i);
446         s.appendFormat("%s: %s", cc, item.asString(false).c_str());
447         if (i != 0) {
448             s.append(", ");
449         }
450     }
451     return s;
452 }
453 
dumpToLog() const454 void MetaDataBase::dumpToLog() const {
455     std::lock_guard<std::mutex> guard(mInternalData->mLock);
456     for (int i = mInternalData->mItems.size(); --i >= 0;) {
457         int32_t key = mInternalData->mItems.keyAt(i);
458         char cc[5];
459         MakeFourCCString(key, cc);
460         const typed_data &item = mInternalData->mItems.valueAt(i);
461         ALOGI("%s: %s", cc, item.asString(true /* verbose */).c_str());
462     }
463 }
464 
465 #if defined(__ANDROID__) && !defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
writeToParcel(Parcel & parcel)466 status_t MetaDataBase::writeToParcel(Parcel &parcel) {
467     status_t ret;
468     std::lock_guard<std::mutex> guard(mInternalData->mLock);
469     size_t numItems = mInternalData->mItems.size();
470     ret = parcel.writeUint32(uint32_t(numItems));
471     if (ret) {
472         return ret;
473     }
474     for (size_t i = 0; i < numItems; i++) {
475         int32_t key = mInternalData->mItems.keyAt(i);
476         const typed_data &item = mInternalData->mItems.valueAt(i);
477         uint32_t type;
478         const void *data;
479         size_t size;
480         item.getData(&type, &data, &size);
481         ret = parcel.writeInt32(key);
482         if (ret) {
483             return ret;
484         }
485         ret = parcel.writeUint32(type);
486         if (ret) {
487             return ret;
488         }
489         if (type == TYPE_NONE) {
490             android::Parcel::WritableBlob blob;
491             ret = parcel.writeUint32(static_cast<uint32_t>(size));
492             if (ret) {
493                 return ret;
494             }
495             ret = parcel.writeBlob(size, false, &blob);
496             if (ret) {
497                 return ret;
498             }
499             memcpy(blob.data(), data, size);
500             blob.release();
501         } else {
502             ret = parcel.writeByteArray(size, (uint8_t*)data);
503             if (ret) {
504                 return ret;
505             }
506         }
507     }
508     return OK;
509 }
510 
updateFromParcel(const Parcel & parcel)511 status_t MetaDataBase::updateFromParcel(const Parcel &parcel) {
512     uint32_t numItems;
513     if (parcel.readUint32(&numItems) == OK) {
514 
515         for (size_t i = 0; i < numItems; i++) {
516             int32_t key;
517             uint32_t type;
518             uint32_t size;
519             status_t ret = parcel.readInt32(&key);
520             ret |= parcel.readUint32(&type);
521             ret |= parcel.readUint32(&size);
522             if (ret != OK) {
523                 break;
524             }
525             // copy data from Blob, which may be inline in Parcel storage,
526             // then advance position
527             if (type == TYPE_NONE) {
528                 android::Parcel::ReadableBlob blob;
529                 ret = parcel.readBlob(size, &blob);
530                 if (ret != OK) {
531                     break;
532                 }
533                 setData(key, type, blob.data(), size);
534                 blob.release();
535             } else if (type == TYPE_C_STRING) {
536                 // copy data directly from Parcel storage, then advance position
537                 // NB: readInplace() bumps position, it is NOT idempotent.
538                 const void *src = parcel.readInplace(size);
539                 char *str = (char *) src;
540                 if (src == nullptr || size == 0 || str[size-1] != '\0') {
541                     char ccKey[5];
542                     MakeFourCCString(key, ccKey);
543                     if (src == nullptr) {
544                         ALOGW("ignoring key '%s' string with no data (expected %d)", ccKey, size);
545                     } else {
546                         ALOGW("ignoring key '%s': unterminated string of %d bytes", ccKey, size);
547                     }
548                 } else {
549                     setData(key, type, src, size);
550                 }
551             } else {
552                 // copy data directly from Parcel storage, then advance position
553                 // verify that the received size is enough
554                 uint32_t needed = 0;
555                 switch (type) {
556                     case TYPE_INT32:
557                         needed = sizeof(int32_t);
558                         break;
559                     case TYPE_INT64:
560                         needed = sizeof(int64_t);
561                         break;
562                     case TYPE_FLOAT:
563                         needed = sizeof(float);
564                         break;
565                     case TYPE_POINTER:
566                         // NB: this rejects passing between 32-bit and 64-bit space.
567                         needed = sizeof(void*);
568                         break;
569                     case TYPE_RECT:
570                         needed = sizeof(Rect);
571                         break;
572                     default:
573                         // non-standard entities can be any size >= 0
574                         needed = 0;
575                         break;
576                 }
577                 const void *src = parcel.readInplace(size);
578                 if (src == nullptr || (needed != 0 && size != needed)) {
579                     char ccKey[5];
580                     MakeFourCCString(key, ccKey);
581                     char ccType[5];
582                     MakeFourCCString(type, ccType);
583                     if (src == nullptr) {
584                         ALOGW("ignoring key '%s' type '%s' missing data (expected %d)",
585                               ccKey, ccType, size);
586                     } else {
587                         ALOGW("ignoring key '%s': type '%s' bytes: expected %d != %d received",
588                                ccKey, ccType, needed, size);
589                     }
590                 } else {
591                     setData(key, type, src, size);
592                 }
593             }
594          }
595 
596         return OK;
597     }
598     ALOGW("no metadata in parcel");
599     return UNKNOWN_ERROR;
600 }
601 #endif // defined(__ANDROID__) && !defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
602 
603 }  // namespace android
604 
605