Loading camera/CameraMetadata.cpp +73 −1 Original line number Diff line number Diff line Loading @@ -22,7 +22,6 @@ #include <binder/Parcel.h> #include <camera/CameraMetadata.h> #include <camera/VendorTagDescriptor.h> namespace android { Loading Loading @@ -409,6 +408,79 @@ status_t CameraMetadata::erase(uint32_t tag) { return res; } status_t CameraMetadata::removePermissionEntries(metadata_vendor_id_t vendorId, std::vector<int32_t> *tagsRemoved) { uint32_t tagCount = 0; std::vector<uint32_t> tagsToRemove; if (tagsRemoved == nullptr) { return BAD_VALUE; } sp<VendorTagDescriptor> vTags = VendorTagDescriptor::getGlobalVendorTagDescriptor(); if ((nullptr == vTags.get()) || (0 >= vTags->getTagCount())) { sp<VendorTagDescriptorCache> cache = VendorTagDescriptorCache::getGlobalVendorTagCache(); if (cache.get()) { cache->getVendorTagDescriptor(vendorId, &vTags); } } if ((nullptr != vTags.get()) && (vTags->getTagCount() > 0)) { tagCount = vTags->getTagCount(); uint32_t *vendorTags = new uint32_t[tagCount]; if (nullptr == vendorTags) { return NO_MEMORY; } vTags->getTagArray(vendorTags); tagsToRemove.reserve(tagCount); tagsToRemove.insert(tagsToRemove.begin(), vendorTags, vendorTags + tagCount); delete [] vendorTags; tagCount = 0; } auto tagsNeedingPermission = get_camera_metadata_permission_needed(&tagCount); if (tagCount > 0) { tagsToRemove.reserve(tagsToRemove.capacity() + tagCount); tagsToRemove.insert(tagsToRemove.end(), tagsNeedingPermission, tagsNeedingPermission + tagCount); } tagsRemoved->reserve(tagsToRemove.size()); for (const auto &it : tagsToRemove) { if (exists(it)) { auto rc = erase(it); if (NO_ERROR != rc) { ALOGE("%s: Failed to erase tag: %x", __func__, it); return rc; } tagsRemoved->push_back(it); } } // Update the available characterstics accordingly if (exists(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS)) { std::vector<uint32_t> currentKeys; std::sort(tagsRemoved->begin(), tagsRemoved->end()); auto keys = find(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS); currentKeys.reserve(keys.count); currentKeys.insert(currentKeys.end(), keys.data.i32, keys.data.i32 + keys.count); std::sort(currentKeys.begin(), currentKeys.end()); std::vector<int32_t> newKeys(keys.count); auto end = std::set_difference(currentKeys.begin(), currentKeys.end(), tagsRemoved->begin(), tagsRemoved->end(), newKeys.begin()); newKeys.resize(end - newKeys.begin()); update(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, newKeys.data(), newKeys.size()); } return NO_ERROR; } void CameraMetadata::dump(int fd, int verbosity, int indentation) const { dump_indented_camera_metadata(mBuffer, fd, verbosity, indentation); } Loading camera/include/camera/CameraMetadata.h +7 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ #include <utils/String8.h> #include <utils/Vector.h> #include <binder/Parcelable.h> #include <camera/VendorTagDescriptor.h> namespace android { Loading Loading @@ -169,6 +170,12 @@ class CameraMetadata: public Parcelable { */ status_t erase(uint32_t tag); /** * Remove metadata entries that need additional permissions. */ status_t removePermissionEntries(metadata_vendor_id_t vendorId, std::vector<int32_t> *tagsRemoved /*out*/); /** * Swap the underlying camera metadata between this and the other * metadata object. Loading camera/tests/Android.mk +2 −1 Original line number Diff line number Diff line Loading @@ -19,7 +19,8 @@ LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_SRC_FILES:= \ VendorTagDescriptorTests.cpp \ CameraBinderTests.cpp \ CameraZSLTests.cpp CameraZSLTests.cpp \ CameraCharacteristicsPermission.cpp LOCAL_SHARED_LIBRARIES := \ liblog \ Loading camera/tests/CameraCharacteristicsPermission.cpp 0 → 100644 +96 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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 "CameraCharacteristicsPermission" #include <gtest/gtest.h> #include <binder/ProcessState.h> #include <utils/Errors.h> #include <utils/Log.h> #include <camera/CameraMetadata.h> #include <camera/Camera.h> #include <android/hardware/ICameraService.h> using namespace android; using namespace android::hardware; class CameraCharacteristicsPermission : public ::testing::Test { protected: CameraCharacteristicsPermission() : numCameras(0){} //Gtest interface void SetUp() override; void TearDown() override; int32_t numCameras; sp<ICameraService> mCameraService; }; void CameraCharacteristicsPermission::SetUp() { ::android::binder::Status rc; ProcessState::self()->startThreadPool(); sp<IServiceManager> sm = defaultServiceManager(); sp<IBinder> binder = sm->getService(String16("media.camera")); mCameraService = interface_cast<ICameraService>(binder); rc = mCameraService->getNumberOfCameras( hardware::ICameraService::CAMERA_TYPE_ALL, &numCameras); EXPECT_TRUE(rc.isOk()); } void CameraCharacteristicsPermission::TearDown() { mCameraService.clear(); } // Revoking and acquiring permissions automatically might not be possible. // Test the functionality for removal of camera characteristics needing // a camera permission. TEST_F(CameraCharacteristicsPermission, TestCameraPermission) { for (int32_t cameraId = 0; cameraId < numCameras; cameraId++) { String16 cameraIdStr = String16(String8::format("%d", cameraId)); bool isSupported = false; auto rc = mCameraService->supportsCameraApi(cameraIdStr, hardware::ICameraService::API_VERSION_2, &isSupported); EXPECT_TRUE(rc.isOk()); if (!isSupported) { continue; } CameraMetadata metadata; std::vector<int32_t> tagsNeedingPermission; rc = mCameraService->getCameraCharacteristics(cameraIdStr, &metadata); ASSERT_TRUE(rc.isOk()); EXPECT_FALSE(metadata.isEmpty()); EXPECT_EQ(metadata.removePermissionEntries(CAMERA_METADATA_INVALID_VENDOR_ID, &tagsNeedingPermission), NO_ERROR); camera_metadata_entry_t availableCharacteristics = metadata.find(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS); EXPECT_TRUE(0 < availableCharacteristics.count); std::vector<uint32_t> availableKeys; availableKeys.reserve(availableCharacteristics.count); availableKeys.insert(availableKeys.begin(), availableCharacteristics.data.i32, availableCharacteristics.data.i32 + availableCharacteristics.count); for (const auto &key : tagsNeedingPermission) { ASSERT_FALSE(metadata.exists(key)); auto it = std::find(availableKeys.begin(), availableKeys.end(), key); ASSERT_TRUE(it == availableKeys.end()); } } } services/camera/libcameraservice/CameraService.cpp +28 −0 Original line number Diff line number Diff line Loading @@ -491,6 +491,34 @@ Status CameraService::getCameraCharacteristics(const String16& cameraId, strerror(-res), res); } int callingPid = getCallingPid(); int callingUid = getCallingUid(); std::vector<int32_t> tagsRemoved; // If it's not calling from cameraserver, check the permission. if ((callingPid != getpid()) && !checkPermission(String16("android.permission.CAMERA"), callingPid, callingUid)) { res = cameraInfo->removePermissionEntries( mCameraProviderManager->getProviderTagIdLocked(String8(cameraId).string()), &tagsRemoved); if (res != OK) { cameraInfo->clear(); return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Failed to remove camera" " characteristics needing camera permission for device %s: %s (%d)", String8(cameraId).string(), strerror(-res), res); } } if (!tagsRemoved.empty()) { res = cameraInfo->update(ANDROID_REQUEST_CHARACTERISTIC_KEYS_NEEDING_PERMISSION, tagsRemoved.data(), tagsRemoved.size()); if (res != OK) { cameraInfo->clear(); return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Failed to insert camera " "keys needing permission for device %s: %s (%d)", String8(cameraId).string(), strerror(-res), res); } } return ret; } Loading Loading
camera/CameraMetadata.cpp +73 −1 Original line number Diff line number Diff line Loading @@ -22,7 +22,6 @@ #include <binder/Parcel.h> #include <camera/CameraMetadata.h> #include <camera/VendorTagDescriptor.h> namespace android { Loading Loading @@ -409,6 +408,79 @@ status_t CameraMetadata::erase(uint32_t tag) { return res; } status_t CameraMetadata::removePermissionEntries(metadata_vendor_id_t vendorId, std::vector<int32_t> *tagsRemoved) { uint32_t tagCount = 0; std::vector<uint32_t> tagsToRemove; if (tagsRemoved == nullptr) { return BAD_VALUE; } sp<VendorTagDescriptor> vTags = VendorTagDescriptor::getGlobalVendorTagDescriptor(); if ((nullptr == vTags.get()) || (0 >= vTags->getTagCount())) { sp<VendorTagDescriptorCache> cache = VendorTagDescriptorCache::getGlobalVendorTagCache(); if (cache.get()) { cache->getVendorTagDescriptor(vendorId, &vTags); } } if ((nullptr != vTags.get()) && (vTags->getTagCount() > 0)) { tagCount = vTags->getTagCount(); uint32_t *vendorTags = new uint32_t[tagCount]; if (nullptr == vendorTags) { return NO_MEMORY; } vTags->getTagArray(vendorTags); tagsToRemove.reserve(tagCount); tagsToRemove.insert(tagsToRemove.begin(), vendorTags, vendorTags + tagCount); delete [] vendorTags; tagCount = 0; } auto tagsNeedingPermission = get_camera_metadata_permission_needed(&tagCount); if (tagCount > 0) { tagsToRemove.reserve(tagsToRemove.capacity() + tagCount); tagsToRemove.insert(tagsToRemove.end(), tagsNeedingPermission, tagsNeedingPermission + tagCount); } tagsRemoved->reserve(tagsToRemove.size()); for (const auto &it : tagsToRemove) { if (exists(it)) { auto rc = erase(it); if (NO_ERROR != rc) { ALOGE("%s: Failed to erase tag: %x", __func__, it); return rc; } tagsRemoved->push_back(it); } } // Update the available characterstics accordingly if (exists(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS)) { std::vector<uint32_t> currentKeys; std::sort(tagsRemoved->begin(), tagsRemoved->end()); auto keys = find(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS); currentKeys.reserve(keys.count); currentKeys.insert(currentKeys.end(), keys.data.i32, keys.data.i32 + keys.count); std::sort(currentKeys.begin(), currentKeys.end()); std::vector<int32_t> newKeys(keys.count); auto end = std::set_difference(currentKeys.begin(), currentKeys.end(), tagsRemoved->begin(), tagsRemoved->end(), newKeys.begin()); newKeys.resize(end - newKeys.begin()); update(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, newKeys.data(), newKeys.size()); } return NO_ERROR; } void CameraMetadata::dump(int fd, int verbosity, int indentation) const { dump_indented_camera_metadata(mBuffer, fd, verbosity, indentation); } Loading
camera/include/camera/CameraMetadata.h +7 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ #include <utils/String8.h> #include <utils/Vector.h> #include <binder/Parcelable.h> #include <camera/VendorTagDescriptor.h> namespace android { Loading Loading @@ -169,6 +170,12 @@ class CameraMetadata: public Parcelable { */ status_t erase(uint32_t tag); /** * Remove metadata entries that need additional permissions. */ status_t removePermissionEntries(metadata_vendor_id_t vendorId, std::vector<int32_t> *tagsRemoved /*out*/); /** * Swap the underlying camera metadata between this and the other * metadata object. Loading
camera/tests/Android.mk +2 −1 Original line number Diff line number Diff line Loading @@ -19,7 +19,8 @@ LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_SRC_FILES:= \ VendorTagDescriptorTests.cpp \ CameraBinderTests.cpp \ CameraZSLTests.cpp CameraZSLTests.cpp \ CameraCharacteristicsPermission.cpp LOCAL_SHARED_LIBRARIES := \ liblog \ Loading
camera/tests/CameraCharacteristicsPermission.cpp 0 → 100644 +96 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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 "CameraCharacteristicsPermission" #include <gtest/gtest.h> #include <binder/ProcessState.h> #include <utils/Errors.h> #include <utils/Log.h> #include <camera/CameraMetadata.h> #include <camera/Camera.h> #include <android/hardware/ICameraService.h> using namespace android; using namespace android::hardware; class CameraCharacteristicsPermission : public ::testing::Test { protected: CameraCharacteristicsPermission() : numCameras(0){} //Gtest interface void SetUp() override; void TearDown() override; int32_t numCameras; sp<ICameraService> mCameraService; }; void CameraCharacteristicsPermission::SetUp() { ::android::binder::Status rc; ProcessState::self()->startThreadPool(); sp<IServiceManager> sm = defaultServiceManager(); sp<IBinder> binder = sm->getService(String16("media.camera")); mCameraService = interface_cast<ICameraService>(binder); rc = mCameraService->getNumberOfCameras( hardware::ICameraService::CAMERA_TYPE_ALL, &numCameras); EXPECT_TRUE(rc.isOk()); } void CameraCharacteristicsPermission::TearDown() { mCameraService.clear(); } // Revoking and acquiring permissions automatically might not be possible. // Test the functionality for removal of camera characteristics needing // a camera permission. TEST_F(CameraCharacteristicsPermission, TestCameraPermission) { for (int32_t cameraId = 0; cameraId < numCameras; cameraId++) { String16 cameraIdStr = String16(String8::format("%d", cameraId)); bool isSupported = false; auto rc = mCameraService->supportsCameraApi(cameraIdStr, hardware::ICameraService::API_VERSION_2, &isSupported); EXPECT_TRUE(rc.isOk()); if (!isSupported) { continue; } CameraMetadata metadata; std::vector<int32_t> tagsNeedingPermission; rc = mCameraService->getCameraCharacteristics(cameraIdStr, &metadata); ASSERT_TRUE(rc.isOk()); EXPECT_FALSE(metadata.isEmpty()); EXPECT_EQ(metadata.removePermissionEntries(CAMERA_METADATA_INVALID_VENDOR_ID, &tagsNeedingPermission), NO_ERROR); camera_metadata_entry_t availableCharacteristics = metadata.find(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS); EXPECT_TRUE(0 < availableCharacteristics.count); std::vector<uint32_t> availableKeys; availableKeys.reserve(availableCharacteristics.count); availableKeys.insert(availableKeys.begin(), availableCharacteristics.data.i32, availableCharacteristics.data.i32 + availableCharacteristics.count); for (const auto &key : tagsNeedingPermission) { ASSERT_FALSE(metadata.exists(key)); auto it = std::find(availableKeys.begin(), availableKeys.end(), key); ASSERT_TRUE(it == availableKeys.end()); } } }
services/camera/libcameraservice/CameraService.cpp +28 −0 Original line number Diff line number Diff line Loading @@ -491,6 +491,34 @@ Status CameraService::getCameraCharacteristics(const String16& cameraId, strerror(-res), res); } int callingPid = getCallingPid(); int callingUid = getCallingUid(); std::vector<int32_t> tagsRemoved; // If it's not calling from cameraserver, check the permission. if ((callingPid != getpid()) && !checkPermission(String16("android.permission.CAMERA"), callingPid, callingUid)) { res = cameraInfo->removePermissionEntries( mCameraProviderManager->getProviderTagIdLocked(String8(cameraId).string()), &tagsRemoved); if (res != OK) { cameraInfo->clear(); return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Failed to remove camera" " characteristics needing camera permission for device %s: %s (%d)", String8(cameraId).string(), strerror(-res), res); } } if (!tagsRemoved.empty()) { res = cameraInfo->update(ANDROID_REQUEST_CHARACTERISTIC_KEYS_NEEDING_PERMISSION, tagsRemoved.data(), tagsRemoved.size()); if (res != OK) { cameraInfo->clear(); return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Failed to insert camera " "keys needing permission for device %s: %s (%d)", String8(cameraId).string(), strerror(-res), res); } } return ret; } Loading