status_t CameraMetadata::updateImpl(uint32_t tag, const void *data,
        size_t data_count) {
    status_t res;
    if (mLocked) {
        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
        return INVALID_OPERATION;
    }
    int type = get_camera_metadata_tag_type(tag);
    if (type == -1) {
        ALOGE("%s: Tag %d not found", __FUNCTION__, tag);
        return BAD_VALUE;
    }
    // Safety check - ensure that data isn't pointing to this metadata, since
    // that would get invalidated if a resize is needed
    size_t bufferSize = get_camera_metadata_size(mBuffer);
    uintptr_t bufAddr = reinterpret_cast<uintptr_t>(mBuffer);
    uintptr_t dataAddr = reinterpret_cast<uintptr_t>(data);
    if (dataAddr > bufAddr && dataAddr < (bufAddr + bufferSize)) {
        ALOGE("%s: Update attempted with data from the same metadata buffer!",
                __FUNCTION__);
        return INVALID_OPERATION;
    }

    size_t data_size = calculate_camera_metadata_entry_data_size(type,
            data_count);

    res = resizeIfNeeded(1, data_size);

    if (res == OK) {
        camera_metadata_entry_t entry;
        res = find_camera_metadata_entry(mBuffer, tag, &entry);
        if (res == NAME_NOT_FOUND) {
            res = add_camera_metadata_entry(mBuffer,
                    tag, data, data_count);
        } else if (res == OK) {
            res = update_camera_metadata_entry(mBuffer,
                    entry.index, data, data_count, NULL);
        }
    }

    if (res != OK) {
        ALOGE("%s: Unable to update metadata entry %s.%s (%x): %s (%d)",
                __FUNCTION__, get_camera_metadata_section_name(tag),
                get_camera_metadata_tag_name(tag), tag, strerror(-res), res);
    }

    IF_ALOGV() {
        ALOGE_IF(validate_camera_metadata_structure(mBuffer, /*size*/NULL) !=
                 OK,

                 "%s: Failed to validate metadata structure after update %p",
                 __FUNCTION__, mBuffer);
    }

    return res;
}
void CameraMetadata::acquire(camera_metadata_t *buffer) {
    if (mLocked) {
        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
        return;
    }
    clear();
    mBuffer = buffer;

    ALOGE_IF(validate_camera_metadata_structure(mBuffer, /*size*/NULL) != OK,
             "%s: Failed to validate metadata structure %p",
             __FUNCTION__, buffer);
}
status_t CameraMetadata::updateImpl(uint32_t tag, const void *data,
        size_t data_count) {
    status_t res;
    if (mLocked) {
        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
        return INVALID_OPERATION;
    }
    int type = get_camera_metadata_tag_type(tag);
    if (type == -1) {
        ALOGE("%s: Tag %d not found", __FUNCTION__, tag);
        return BAD_VALUE;
    }
    size_t data_size = calculate_camera_metadata_entry_data_size(type,
            data_count);

    res = resizeIfNeeded(1, data_size);

    if (res == OK) {
        camera_metadata_entry_t entry;
        res = find_camera_metadata_entry(mBuffer, tag, &entry);
        if (res == NAME_NOT_FOUND) {
            res = add_camera_metadata_entry(mBuffer,
                    tag, data, data_count);
        } else if (res == OK) {
            res = update_camera_metadata_entry(mBuffer,
                    entry.index, data, data_count, NULL);
        }
    }

    if (res != OK) {
        ALOGE("%s: Unable to update metadata entry %s.%s (%x): %s (%d)",
                __FUNCTION__, get_camera_metadata_section_name(tag),
                get_camera_metadata_tag_name(tag), tag, strerror(-res), res);
    }

    IF_ALOGV() {
        ALOGE_IF(validate_camera_metadata_structure(mBuffer, /*size*/NULL) !=
                 OK,

                 "%s: Failed to validate metadata structure after update %p",
                 __FUNCTION__, mBuffer);
    }

    return res;
}
status_t CameraMetadata::writeToParcel(Parcel& data,
                                       const camera_metadata_t* metadata) {
    status_t res = OK;

    /**
     * Below is the camera metadata parcel layout:
     *
     * |--------------------------------------------|
     * |             arg0: blobSize                 |
     * |              (length = 4)                  |
     * |--------------------------------------------|<--Skip the rest if blobSize == 0.
     * |                                            |
     * |                                            |
     * |              arg1: blob                    |
     * | (length = variable, see arg1 layout below) |
     * |                                            |
     * |                                            |
     * |--------------------------------------------|
     * |              arg2: offset                  |
     * |              (length = 4)                  |
     * |--------------------------------------------|
     */

    // arg0 = blobSize (int32)
    if (metadata == NULL) {
        // Write zero blobSize for null metadata.
        return data.writeInt32(0);
    }

    /**
     * Always make the blob size sufficiently larger, as we need put alignment
     * padding and metadata into the blob. Since we don't know the alignment
     * offset before writeBlob. Then write the metadata to aligned offset.
     */
    const size_t metadataSize = get_camera_metadata_compact_size(metadata);
    const size_t alignment = get_camera_metadata_alignment();
    const size_t blobSize = metadataSize + alignment;
    res = data.writeInt32(static_cast<int32_t>(blobSize));
    if (res != OK) {
        return res;
    }

    size_t offset = 0;
    /**
     * arg1 = metadata (blob).
     *
     * The blob size is the sum of front padding size, metadata size and back padding
     * size, which is equal to metadataSize + alignment.
     *
     * The blob layout is:
     * |------------------------------------|<----Start address of the blob (unaligned).
     * |           front padding            |
     * |          (size = offset)           |
     * |------------------------------------|<----Aligned start address of metadata.
     * |                                    |
     * |                                    |
     * |            metadata                |
     * |       (size = metadataSize)        |
     * |                                    |
     * |                                    |
     * |------------------------------------|
     * |           back padding             |
     * |     (size = alignment - offset)    |
     * |------------------------------------|<----End address of blob.
     *                                            (Blob start address + blob size).
     */
    WritableBlob blob;
    do {
        res = data.writeBlob(blobSize, &blob);
        if (res != OK) {
            break;
        }
        const uintptr_t metadataStart = ALIGN_TO(blob.data(), alignment);
        offset = metadataStart - reinterpret_cast<uintptr_t>(blob.data());
        ALOGV("%s: alignment is: %zu, metadata start: %p, offset: %zu",
                __FUNCTION__, alignment,
                reinterpret_cast<const void *>(metadataStart), offset);
        copy_camera_metadata(reinterpret_cast<void*>(metadataStart), metadataSize, metadata);

        // Not too big of a problem since receiving side does hard validation
        // Don't check the size since the compact size could be larger
        if (validate_camera_metadata_structure(metadata, /*size*/NULL) != OK) {
            ALOGW("%s: Failed to validate metadata %p before writing blob",
                   __FUNCTION__, metadata);
        }

    } while(false);
    blob.release();

    // arg2 = offset (int32)
    res = data.writeInt32(static_cast<int32_t>(offset));

    return res;
}