From d1176ef16677b6c94fb893edb6a864cdccc0b190 Mon Sep 17 00:00:00 2001 From: Ruben Brunk Date: Fri, 21 Feb 2014 10:51:38 -0800 Subject: camera3: Pass vendor tags through binder. Bug: 12134423 - Adds a class for parceling vendor tag definitions. - Passes vendor tag definitions to clients of the camera service. - Switches over to new vendor tag mechanism when reading from HAL. Change-Id: Icef3fe9e67160767bdb8244ac49c85b68b497123 --- camera/Android.mk | 16 ++ camera/ICameraService.cpp | 36 ++++ camera/VendorTagDescriptor.cpp | 319 ++++++++++++++++++++++++++++++ camera/tests/Android.mk | 17 ++ camera/tests/VendorTagDescriptorTests.cpp | 204 +++++++++++++++++++ 5 files changed, 592 insertions(+) create mode 100644 camera/VendorTagDescriptor.cpp create mode 100644 camera/tests/VendorTagDescriptorTests.cpp (limited to 'camera') diff --git a/camera/Android.mk b/camera/Android.mk index e633450..369d0c5 100644 --- a/camera/Android.mk +++ b/camera/Android.mk @@ -1,3 +1,17 @@ +# Copyright 2010 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + CAMERA_CLIENT_LOCAL_PATH:= $(call my-dir) include $(call all-subdir-makefiles) include $(CLEAR_VARS) @@ -21,6 +35,7 @@ LOCAL_SRC_FILES:= \ camera2/CaptureRequest.cpp \ ProCamera.cpp \ CameraBase.cpp \ + VendorTagDescriptor.cpp LOCAL_SHARED_LIBRARIES := \ libcutils \ @@ -34,6 +49,7 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_C_INCLUDES += \ system/media/camera/include \ + system/media/private/camera/include LOCAL_MODULE:= libcamera_client diff --git a/camera/ICameraService.cpp b/camera/ICameraService.cpp index 5fc89fb..ef6c0f4 100644 --- a/camera/ICameraService.cpp +++ b/camera/ICameraService.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "BpCameraService" #include +#include #include #include @@ -34,6 +35,7 @@ #include #include #include +#include namespace android { @@ -143,6 +145,24 @@ public: return result; } + // Get enumeration and description of vendor tags for camera + virtual status_t getCameraVendorTagDescriptor(/*out*/sp& desc) { + Parcel data, reply; + data.writeInterfaceToken(ICameraService::getInterfaceDescriptor()); + remote()->transact(BnCameraService::GET_CAMERA_VENDOR_TAG_DESCRIPTOR, data, &reply); + + if (readExceptionCode(reply)) return -EPROTO; + status_t result = reply.readInt32(); + + if (reply.readInt32() != 0) { + sp d; + if (VendorTagDescriptor::createFromParcel(&reply, /*out*/d) == OK) { + desc = d; + } + } + return result; + } + // connect to camera service (android.hardware.Camera) virtual status_t connect(const sp& cameraClient, int cameraId, const String16 &clientPackageName, int clientUid, @@ -275,6 +295,22 @@ status_t BnCameraService::onTransact( info.writeToParcel(reply); return NO_ERROR; } break; + case GET_CAMERA_VENDOR_TAG_DESCRIPTOR: { + CHECK_INTERFACE(ICameraService, data, reply); + sp d; + status_t result = getCameraVendorTagDescriptor(d); + reply->writeNoException(); + reply->writeInt32(result); + + // out-variables are after exception and return value + reply->writeInt32(1); // means the parcelable is included + if (d == NULL) { + reply->writeInt32(0); + } else { + d->writeToParcel(reply); + } + return NO_ERROR; + } break; case CONNECT: { CHECK_INTERFACE(ICameraService, data, reply); sp cameraClient = diff --git a/camera/VendorTagDescriptor.cpp b/camera/VendorTagDescriptor.cpp new file mode 100644 index 0000000..89b0ea8 --- /dev/null +++ b/camera/VendorTagDescriptor.cpp @@ -0,0 +1,319 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "VenderTagDescriptor" + +#include +#include +#include +#include +#include +#include +#include + +#include "camera/VendorTagDescriptor.h" + +#include + +namespace android { + +extern "C" { + +static int vendor_tag_descriptor_get_tag_count(const vendor_tag_ops_t* v); +static void vendor_tag_descriptor_get_all_tags(const vendor_tag_ops_t* v, uint32_t* tagArray); +static const char* vendor_tag_descriptor_get_section_name(const vendor_tag_ops_t* v, uint32_t tag); +static const char* vendor_tag_descriptor_get_tag_name(const vendor_tag_ops_t* v, uint32_t tag); +static int vendor_tag_descriptor_get_tag_type(const vendor_tag_ops_t* v, uint32_t tag); + +} /* extern "C" */ + + +static Mutex sLock; +static sp sGlobalVendorTagDescriptor; + +VendorTagDescriptor::VendorTagDescriptor() {} +VendorTagDescriptor::~VendorTagDescriptor() {} + +status_t VendorTagDescriptor::createDescriptorFromOps(const vendor_tag_ops_t* vOps, + /*out*/ + sp& descriptor) { + if (vOps == NULL) { + ALOGE("%s: vendor_tag_ops argument was NULL.", __FUNCTION__); + return BAD_VALUE; + } + + int tagCount = vOps->get_tag_count(vOps); + if (tagCount < 0 || tagCount > INT32_MAX) { + ALOGE("%s: tag count %d from vendor ops is invalid.", __FUNCTION__, tagCount); + return BAD_VALUE; + } + + Vector tagArray; + LOG_ALWAYS_FATAL_IF(tagArray.resize(tagCount) != tagCount, + "%s: too many (%u) vendor tags defined.", __FUNCTION__, tagCount); + + vOps->get_all_tags(vOps, /*out*/tagArray.editArray()); + + sp desc = new VendorTagDescriptor(); + desc->mTagCount = tagCount; + + for (size_t i = 0; i < static_cast(tagCount); ++i) { + uint32_t tag = tagArray[i]; + if (tag < CAMERA_METADATA_VENDOR_TAG_BOUNDARY) { + ALOGE("%s: vendor tag %d not in vendor tag section.", __FUNCTION__, tag); + return BAD_VALUE; + } + const char *tagName = vOps->get_tag_name(vOps, tag); + if (tagName == NULL) { + ALOGE("%s: no tag name defined for vendor tag %d.", __FUNCTION__, tag); + return BAD_VALUE; + } + desc->mTagToNameMap.add(tag, String8(tagName)); + const char *sectionName = vOps->get_section_name(vOps, tag); + if (sectionName == NULL) { + ALOGE("%s: no section name defined for vendor tag %d.", __FUNCTION__, tag); + return BAD_VALUE; + } + desc->mTagToSectionMap.add(tag, String8(sectionName)); + int tagType = vOps->get_tag_type(vOps, tag); + if (tagType < 0 || tagType >= NUM_TYPES) { + ALOGE("%s: tag type %d from vendor ops does not exist.", __FUNCTION__, tagType); + return BAD_VALUE; + } + desc->mTagToTypeMap.add(tag, tagType); + } + descriptor = desc; + return OK; +} + +status_t VendorTagDescriptor::createFromParcel(const Parcel* parcel, + /*out*/ + sp& descriptor) { + status_t res = OK; + if (parcel == NULL) { + ALOGE("%s: parcel argument was NULL.", __FUNCTION__); + return BAD_VALUE; + } + + int32_t tagCount = 0; + if ((res = parcel->readInt32(&tagCount)) != OK) { + ALOGE("%s: could not read tag count from parcel", __FUNCTION__); + return res; + } + + if (tagCount < 0 || tagCount > INT32_MAX) { + ALOGE("%s: tag count %d from vendor ops is invalid.", __FUNCTION__, tagCount); + return BAD_VALUE; + } + + sp desc = new VendorTagDescriptor(); + desc->mTagCount = tagCount; + + uint32_t tag; + int32_t tagType; + for (int32_t i = 0; i < tagCount; ++i) { + if ((res = parcel->readInt32(reinterpret_cast(&tag))) != OK) { + ALOGE("%s: could not read tag id from parcel for index %d", __FUNCTION__, i); + break; + } + if (tag < CAMERA_METADATA_VENDOR_TAG_BOUNDARY) { + ALOGE("%s: vendor tag %d not in vendor tag section.", __FUNCTION__, tag); + res = BAD_VALUE; + break; + } + if ((res = parcel->readInt32(&tagType)) != OK) { + ALOGE("%s: could not read tag type from parcel for tag %d", __FUNCTION__, tag); + break; + } + if (tagType < 0 || tagType >= NUM_TYPES) { + ALOGE("%s: tag type %d from vendor ops does not exist.", __FUNCTION__, tagType); + res = BAD_VALUE; + break; + } + String8 tagName = parcel->readString8(); + if (tagName.isEmpty()) { + ALOGE("%s: parcel tag name was NULL for tag %d.", __FUNCTION__, tag); + res = NOT_ENOUGH_DATA; + break; + } + String8 sectionName = parcel->readString8(); + if (sectionName.isEmpty()) { + ALOGE("%s: parcel section name was NULL for tag %d.", __FUNCTION__, tag); + res = NOT_ENOUGH_DATA; + break; + } + + desc->mTagToNameMap.add(tag, tagName); + desc->mTagToSectionMap.add(tag, sectionName); + desc->mTagToTypeMap.add(tag, tagType); + } + + if (res != OK) { + return res; + } + + descriptor = desc; + return res; +} + +int VendorTagDescriptor::getTagCount() const { + size_t size = mTagToNameMap.size(); + if (size == 0) { + return VENDOR_TAG_COUNT_ERR; + } + return size; +} + +void VendorTagDescriptor::getTagArray(uint32_t* tagArray) const { + size_t size = mTagToNameMap.size(); + for (size_t i = 0; i < size; ++i) { + tagArray[i] = mTagToNameMap.keyAt(i); + } +} + +const char* VendorTagDescriptor::getSectionName(uint32_t tag) const { + ssize_t index = mTagToSectionMap.indexOfKey(tag); + if (index < 0) { + return VENDOR_SECTION_NAME_ERR; + } + return mTagToSectionMap.valueAt(index).string(); +} + +const char* VendorTagDescriptor::getTagName(uint32_t tag) const { + ssize_t index = mTagToNameMap.indexOfKey(tag); + if (index < 0) { + return VENDOR_TAG_NAME_ERR; + } + return mTagToNameMap.valueAt(index).string(); +} + +int VendorTagDescriptor::getTagType(uint32_t tag) const { + ssize_t index = mTagToNameMap.indexOfKey(tag); + if (index < 0) { + return VENDOR_TAG_TYPE_ERR; + } + return mTagToTypeMap.valueFor(tag); +} + +status_t VendorTagDescriptor::writeToParcel(Parcel* parcel) const { + status_t res = OK; + if (parcel == NULL) { + ALOGE("%s: parcel argument was NULL.", __FUNCTION__); + return BAD_VALUE; + } + + if ((res = parcel->writeInt32(mTagCount)) != OK) { + return res; + } + + size_t size = mTagToNameMap.size(); + uint32_t tag; + int32_t tagType; + for (size_t i = 0; i < size; ++i) { + tag = mTagToNameMap.keyAt(i); + String8 tagName = mTagToNameMap[i]; + String8 sectionName = mTagToSectionMap.valueFor(tag); + tagType = mTagToTypeMap.valueFor(tag); + if ((res = parcel->writeInt32(tag)) != OK) break; + if ((res = parcel->writeInt32(tagType)) != OK) break; + if ((res = parcel->writeString8(tagName)) != OK) break; + if ((res = parcel->writeString8(sectionName)) != OK) break; + } + + return res; +} + +status_t VendorTagDescriptor::setAsGlobalVendorTagDescriptor(sp& desc) { + status_t res = OK; + Mutex::Autolock al(sLock); + sGlobalVendorTagDescriptor = desc; + + vendor_tag_ops_t* opsPtr = NULL; + if (desc != NULL) { + opsPtr = &(desc->mVendorOps); + opsPtr->get_tag_count = vendor_tag_descriptor_get_tag_count; + opsPtr->get_all_tags = vendor_tag_descriptor_get_all_tags; + opsPtr->get_section_name = vendor_tag_descriptor_get_section_name; + opsPtr->get_tag_name = vendor_tag_descriptor_get_tag_name; + opsPtr->get_tag_type = vendor_tag_descriptor_get_tag_type; + } + if((res = set_camera_metadata_vendor_ops(opsPtr)) != OK) { + ALOGE("%s: Could not set vendor tag descriptor, received error %s (%d)." + , __FUNCTION__, strerror(-res), res); + } + return res; +} + +void VendorTagDescriptor::clearGlobalVendorTagDescriptor() { + Mutex::Autolock al(sLock); + set_camera_metadata_vendor_ops(NULL); + sGlobalVendorTagDescriptor.clear(); +} + +sp VendorTagDescriptor::getGlobalVendorTagDescriptor() { + Mutex::Autolock al(sLock); + return sGlobalVendorTagDescriptor; +} + +extern "C" { + +int vendor_tag_descriptor_get_tag_count(const vendor_tag_ops_t* v) { + Mutex::Autolock al(sLock); + if (sGlobalVendorTagDescriptor == NULL) { + ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__); + return VENDOR_TAG_COUNT_ERR; + } + return sGlobalVendorTagDescriptor->getTagCount(); +} + +void vendor_tag_descriptor_get_all_tags(const vendor_tag_ops_t* v, uint32_t* tagArray) { + Mutex::Autolock al(sLock); + if (sGlobalVendorTagDescriptor == NULL) { + ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__); + return; + } + sGlobalVendorTagDescriptor->getTagArray(tagArray); +} + +const char* vendor_tag_descriptor_get_section_name(const vendor_tag_ops_t* v, uint32_t tag) { + Mutex::Autolock al(sLock); + if (sGlobalVendorTagDescriptor == NULL) { + ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__); + return VENDOR_SECTION_NAME_ERR; + } + return sGlobalVendorTagDescriptor->getSectionName(tag); +} + +const char* vendor_tag_descriptor_get_tag_name(const vendor_tag_ops_t* v, uint32_t tag) { + Mutex::Autolock al(sLock); + if (sGlobalVendorTagDescriptor == NULL) { + ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__); + return VENDOR_TAG_NAME_ERR; + } + return sGlobalVendorTagDescriptor->getTagName(tag); +} + +int vendor_tag_descriptor_get_tag_type(const vendor_tag_ops_t* v, uint32_t tag) { + Mutex::Autolock al(sLock); + if (sGlobalVendorTagDescriptor == NULL) { + ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__); + return VENDOR_TAG_TYPE_ERR; + } + return sGlobalVendorTagDescriptor->getTagType(tag); +} + +} /* extern "C" */ +} /* namespace android */ diff --git a/camera/tests/Android.mk b/camera/tests/Android.mk index ec13911..61385e5 100644 --- a/camera/tests/Android.mk +++ b/camera/tests/Android.mk @@ -1,9 +1,24 @@ +# Copyright 2013 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ main.cpp \ ProCameraTests.cpp \ + VendorTagDescriptorTests.cpp LOCAL_SHARED_LIBRARIES := \ libutils \ @@ -26,6 +41,8 @@ LOCAL_C_INCLUDES += \ external/gtest/include \ external/stlport/stlport \ system/media/camera/include \ + system/media/private/camera/include \ + system/media/camera/tests \ frameworks/av/services/camera/libcameraservice \ frameworks/av/include/camera \ frameworks/native/include \ diff --git a/camera/tests/VendorTagDescriptorTests.cpp b/camera/tests/VendorTagDescriptorTests.cpp new file mode 100644 index 0000000..6624e79 --- /dev/null +++ b/camera/tests/VendorTagDescriptorTests.cpp @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_NDEBUG 0 +#define LOG_TAG "VendorTagDescriptorTests" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace android; + +enum { + BAD_TAG_ARRAY = 0xDEADBEEFu, + BAD_TAG = 0x8DEADBADu, +}; + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +static bool ContainsTag(uint32_t* tagArray, size_t size, uint32_t tag) { + for (size_t i = 0; i < size; ++i) { + if (tag == tagArray[i]) return true; + } + return false; +} + +#define EXPECT_CONTAINS_TAG(t, a) \ + EXPECT_TRUE(ContainsTag(a, ARRAY_SIZE(a), t)) + +#define ASSERT_NOT_NULL(x) \ + ASSERT_TRUE((x) != NULL) + +extern "C" { + +static int default_get_tag_count(const vendor_tag_ops_t* vOps) { + return VENDOR_TAG_COUNT_ERR; +} + +static void default_get_all_tags(const vendor_tag_ops_t* vOps, uint32_t* tagArray) { + //Noop +} + +static const char* default_get_section_name(const vendor_tag_ops_t* vOps, uint32_t tag) { + return VENDOR_SECTION_NAME_ERR; +} + +static const char* default_get_tag_name(const vendor_tag_ops_t* vOps, uint32_t tag) { + return VENDOR_TAG_NAME_ERR; +} + +static int default_get_tag_type(const vendor_tag_ops_t* vOps, uint32_t tag) { + return VENDOR_TAG_TYPE_ERR; +} + +} /*extern "C"*/ + +// Set default vendor operations for a vendor_tag_ops struct +static void FillWithDefaults(vendor_tag_ops_t* vOps) { + ASSERT_NOT_NULL(vOps); + vOps->get_tag_count = default_get_tag_count; + vOps->get_all_tags = default_get_all_tags; + vOps->get_section_name = default_get_section_name; + vOps->get_tag_name = default_get_tag_name; + vOps->get_tag_type = default_get_tag_type; +} + +/** + * Test if values from VendorTagDescriptor methods match corresponding values + * from vendor_tag_ops functions. + */ +TEST(VendorTagDescriptorTest, ConsistentWithVendorTags) { + sp vDesc; + const vendor_tag_ops_t *vOps = &fakevendor_ops; + EXPECT_EQ(OK, VendorTagDescriptor::createDescriptorFromOps(vOps, /*out*/vDesc)); + + ASSERT_NOT_NULL(vDesc); + + // Ensure reasonable tag count + int tagCount = vDesc->getTagCount(); + EXPECT_EQ(tagCount, vOps->get_tag_count(vOps)); + + uint32_t descTagArray[tagCount]; + uint32_t opsTagArray[tagCount]; + + // Get all tag ids + vDesc->getTagArray(descTagArray); + vOps->get_all_tags(vOps, opsTagArray); + + ASSERT_NOT_NULL(descTagArray); + ASSERT_NOT_NULL(opsTagArray); + + uint32_t tag; + for (int i = 0; i < tagCount; ++i) { + // For each tag id, check whether type, section name, tag name match + tag = descTagArray[i]; + EXPECT_CONTAINS_TAG(tag, opsTagArray); + EXPECT_EQ(vDesc->getTagType(tag), vOps->get_tag_type(vOps, tag)); + EXPECT_STREQ(vDesc->getSectionName(tag), vOps->get_section_name(vOps, tag)); + EXPECT_STREQ(vDesc->getTagName(tag), vOps->get_tag_name(vOps, tag)); + } +} + +/** + * Test if values from VendorTagDescriptor methods stay consistent after being + * parcelled/unparcelled. + */ +TEST(VendorTagDescriptorTest, ConsistentAcrossParcel) { + sp vDescOriginal, vDescParceled; + const vendor_tag_ops_t *vOps = &fakevendor_ops; + EXPECT_EQ(OK, VendorTagDescriptor::createDescriptorFromOps(vOps, /*out*/vDescOriginal)); + + ASSERT_TRUE(vDescOriginal != NULL); + + Parcel p; + + // Check whether parcel read/write succeed + EXPECT_EQ(OK, vDescOriginal->writeToParcel(&p)); + p.setDataPosition(0); + ASSERT_EQ(OK, VendorTagDescriptor::createFromParcel(&p, vDescParceled)); + + // Ensure consistent tag count + int tagCount = vDescOriginal->getTagCount(); + ASSERT_EQ(tagCount, vDescParceled->getTagCount()); + + uint32_t descTagArray[tagCount]; + uint32_t desc2TagArray[tagCount]; + + // Get all tag ids + vDescOriginal->getTagArray(descTagArray); + vDescParceled->getTagArray(desc2TagArray); + + ASSERT_NOT_NULL(descTagArray); + ASSERT_NOT_NULL(desc2TagArray); + + uint32_t tag; + for (int i = 0; i < tagCount; ++i) { + // For each tag id, check consistency between the two vendor tag + // descriptors for each type, section name, tag name + tag = descTagArray[i]; + EXPECT_CONTAINS_TAG(tag, desc2TagArray); + EXPECT_EQ(vDescOriginal->getTagType(tag), vDescParceled->getTagType(tag)); + EXPECT_STREQ(vDescOriginal->getSectionName(tag), vDescParceled->getSectionName(tag)); + EXPECT_STREQ(vDescOriginal->getTagName(tag), vDescParceled->getTagName(tag)); + } +} + +/** + * Test defaults and error conditions. + */ +TEST(VendorTagDescriptorTest, ErrorConditions) { + sp vDesc; + vendor_tag_ops_t vOps; + FillWithDefaults(&vOps); + + // Ensure create fails when using null vOps + EXPECT_EQ(BAD_VALUE, VendorTagDescriptor::createDescriptorFromOps(/*vOps*/NULL, vDesc)); + + // Ensure create works when there are no vtags defined in a well-formed vOps + ASSERT_EQ(OK, VendorTagDescriptor::createDescriptorFromOps(&vOps, vDesc)); + + // Ensure defaults are returned when no vtags are defined, or tag is unknown + EXPECT_EQ(VENDOR_TAG_COUNT_ERR, vDesc->getTagCount()); + uint32_t* tagArray = reinterpret_cast(BAD_TAG_ARRAY); + uint32_t* testArray = tagArray; + vDesc->getTagArray(tagArray); + EXPECT_EQ(testArray, tagArray); + EXPECT_EQ(VENDOR_SECTION_NAME_ERR, vDesc->getSectionName(BAD_TAG)); + EXPECT_EQ(VENDOR_TAG_NAME_ERR, vDesc->getTagName(BAD_TAG)); + EXPECT_EQ(VENDOR_TAG_TYPE_ERR, vDesc->getTagType(BAD_TAG)); + + // Make sure global can be set/cleared + const vendor_tag_ops_t *fakeOps = &fakevendor_ops; + sp prevGlobal = VendorTagDescriptor::getGlobalVendorTagDescriptor(); + VendorTagDescriptor::clearGlobalVendorTagDescriptor(); + + EXPECT_TRUE(VendorTagDescriptor::getGlobalVendorTagDescriptor() == NULL); + EXPECT_EQ(OK, VendorTagDescriptor::setAsGlobalVendorTagDescriptor(vDesc)); + EXPECT_TRUE(VendorTagDescriptor::getGlobalVendorTagDescriptor() != NULL); + EXPECT_EQ(VENDOR_SECTION_NAME_ERR, vDesc->getSectionName(BAD_TAG)); + EXPECT_EQ(OK, VendorTagDescriptor::setAsGlobalVendorTagDescriptor(prevGlobal)); + EXPECT_EQ(prevGlobal, VendorTagDescriptor::getGlobalVendorTagDescriptor()); +} + -- cgit v1.1