Loading services/camera/virtualcamera/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -54,6 +54,7 @@ cc_library_static { "util/EglProgram.cc", "util/EglSurfaceTexture.cc", "util/EglUtil.cc", "util/Permissions.cc" ], defaults: [ "libvirtualcamera_defaults", Loading services/camera/virtualcamera/VirtualCameraService.cc +26 −2 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ #include "android/binder_auto_utils.h" #include "android/binder_libbinder.h" #include "binder/Status.h" #include "util/Permissions.h" #include "util/Util.h" using ::android::binder::Status; Loading @@ -54,6 +55,8 @@ Available commands: * enable_test_camera * disable_test_camera )"; constexpr char kCreateVirtualDevicePermission[] = "android.permission.CREATE_VIRTUAL_DEVICE"; ndk::ScopedAStatus validateConfiguration( const VirtualCameraConfiguration& configuration) { Loading @@ -79,17 +82,26 @@ ndk::ScopedAStatus validateConfiguration( } // namespace VirtualCameraService::VirtualCameraService( std::shared_ptr<VirtualCameraProvider> virtualCameraProvider) : mVirtualCameraProvider(virtualCameraProvider) { std::shared_ptr<VirtualCameraProvider> virtualCameraProvider, const PermissionsProxy& permissionProxy) : mVirtualCameraProvider(virtualCameraProvider), mPermissionProxy(permissionProxy) { } ndk::ScopedAStatus VirtualCameraService::registerCamera( const ::ndk::SpAIBinder& token, const VirtualCameraConfiguration& configuration, bool* _aidl_return) { if (!mPermissionProxy.checkCallingPermission(kCreateVirtualDevicePermission)) { ALOGE("%s: caller (pid %d, uid %d) doesn't hold %s permission", __func__, getpid(), getuid(), kCreateVirtualDevicePermission); return ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY); } if (_aidl_return == nullptr) { return ndk::ScopedAStatus::fromServiceSpecificError( Status::EX_ILLEGAL_ARGUMENT); } *_aidl_return = true; auto status = validateConfiguration(configuration); Loading Loading @@ -127,6 +139,12 @@ ndk::ScopedAStatus VirtualCameraService::registerCamera( ndk::ScopedAStatus VirtualCameraService::unregisterCamera( const ::ndk::SpAIBinder& token) { if (!mPermissionProxy.checkCallingPermission(kCreateVirtualDevicePermission)) { ALOGE("%s: caller (pid %d, uid %d) doesn't hold %s permission", __func__, getpid(), getuid(), kCreateVirtualDevicePermission); return ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY); } std::lock_guard lock(mLock); auto it = mTokenToCameraName.find(token); Loading @@ -145,6 +163,12 @@ ndk::ScopedAStatus VirtualCameraService::unregisterCamera( ndk::ScopedAStatus VirtualCameraService::getCameraId( const ::ndk::SpAIBinder& token, int32_t* _aidl_return) { if (!mPermissionProxy.checkCallingPermission(kCreateVirtualDevicePermission)) { ALOGE("%s: caller (pid %d, uid %d) doesn't hold %s permission", __func__, getpid(), getuid(), kCreateVirtualDevicePermission); return ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY); } if (_aidl_return == nullptr) { return ndk::ScopedAStatus::fromServiceSpecificError( Status::EX_ILLEGAL_ARGUMENT); Loading services/camera/virtualcamera/VirtualCameraService.h +5 −1 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include "VirtualCameraDevice.h" #include "VirtualCameraProvider.h" #include "aidl/android/companion/virtualcamera/BnVirtualCameraService.h" #include "util/Permissions.h" namespace android { namespace companion { Loading @@ -34,7 +35,8 @@ class VirtualCameraService : public aidl::android::companion::virtualcamera::BnVirtualCameraService { public: VirtualCameraService( std::shared_ptr<VirtualCameraProvider> virtualCameraProvider); std::shared_ptr<VirtualCameraProvider> virtualCameraProvider, const PermissionsProxy& permissionProxy = PermissionsProxy::get()); // Register camera corresponding to the binder token. ndk::ScopedAStatus registerCamera( Loading Loading @@ -68,6 +70,8 @@ class VirtualCameraService std::shared_ptr<VirtualCameraProvider> mVirtualCameraProvider; const PermissionsProxy& mPermissionProxy; std::mutex mLock; struct BinderTokenHash { std::size_t operator()(const ::ndk::SpAIBinder& key) const { Loading services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc +50 −2 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ #include "binder/Binder.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "util/Permissions.h" #include "utils/Errors.h" namespace android { Loading @@ -50,10 +51,13 @@ using ::testing::Ge; using ::testing::IsEmpty; using ::testing::IsNull; using ::testing::Not; using ::testing::Return; using ::testing::SizeIs; constexpr int kVgaWidth = 640; constexpr int kVgaHeight = 480; constexpr char kCreateVirtualDevicePermissions[] = "android.permission.CREATE_VIRTUAL_DEVICE"; const VirtualCameraConfiguration kEmptyVirtualCameraConfiguration; Loading @@ -76,6 +80,12 @@ class MockCameraProviderCallback : public BnCameraProviderCallback { (override)); }; class MockPermissionsProxy : public PermissionsProxy { public: MOCK_METHOD(bool, checkCallingPermission, (const std::string&), (const override)); }; class VirtualCameraServiceTest : public ::testing::Test { public: void SetUp() override { Loading @@ -87,8 +97,11 @@ class VirtualCameraServiceTest : public ::testing::Test { return ndk::ScopedAStatus::ok(); }); mCameraProvider->setCallback(mMockCameraProviderCallback); mCameraService = ndk::SharedRefBase::make<VirtualCameraService>(mCameraProvider); mCameraService = ndk::SharedRefBase::make<VirtualCameraService>( mCameraProvider, mMockPermissionsProxy); ON_CALL(mMockPermissionsProxy, checkCallingPermission) .WillByDefault(Return(true)); mDevNullFd = open("/dev/null", O_RDWR); ASSERT_THAT(mDevNullFd, Ge(0)); Loading Loading @@ -129,6 +142,7 @@ class VirtualCameraServiceTest : public ::testing::Test { std::shared_ptr<VirtualCameraProvider> mCameraProvider; std::shared_ptr<MockCameraProviderCallback> mMockCameraProviderCallback = ndk::SharedRefBase::make<MockCameraProviderCallback>(); MockPermissionsProxy mMockPermissionsProxy; sp<BBinder> mOwnerToken; ndk::SpAIBinder mNdkOwnerToken; Loading Loading @@ -242,6 +256,40 @@ TEST_F(VirtualCameraServiceTest, UnregisterCamera) { EXPECT_THAT(mCameraService->getCamera(mNdkOwnerToken), IsNull()); } TEST_F(VirtualCameraServiceTest, RegisterCameraWithoutPermissionFails) { bool aidlRet; EXPECT_CALL(mMockPermissionsProxy, checkCallingPermission(kCreateVirtualDevicePermissions)) .WillOnce(Return(false)); EXPECT_THAT(mCameraService ->registerCamera(mNdkOwnerToken, mVgaYUV420OnlyConfiguration, &aidlRet) .getExceptionCode(), Eq(EX_SECURITY)); } TEST_F(VirtualCameraServiceTest, UnregisterCameraWithoutPermissionFails) { EXPECT_CALL(mMockPermissionsProxy, checkCallingPermission(kCreateVirtualDevicePermissions)) .WillOnce(Return(false)); EXPECT_THAT( mCameraService->unregisterCamera(mNdkOwnerToken).getExceptionCode(), Eq(EX_SECURITY)); } TEST_F(VirtualCameraServiceTest, GetIdWithoutPermissionFails) { int32_t aidlRet; EXPECT_CALL(mMockPermissionsProxy, checkCallingPermission(kCreateVirtualDevicePermissions)) .WillOnce(Return(false)); EXPECT_THAT( mCameraService->getCameraId(mNdkOwnerToken, &aidlRet).getExceptionCode(), Eq(EX_SECURITY)); } TEST_F(VirtualCameraServiceTest, UnregisterCameraWithUnknownToken) { createCamera(); Loading services/camera/virtualcamera/util/Permissions.cc 0 → 100644 +55 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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 "VirtualCameraPermissions" #include "Permissions.h" #include "binder/PermissionCache.h" #include "log/log.h" namespace android { namespace companion { namespace virtualcamera { namespace { class PermissionsProxyImpl : public PermissionsProxy { public: bool checkCallingPermission(const std::string& permission) const override; }; bool PermissionsProxyImpl::checkCallingPermission( const std::string& permission) const { int32_t uid; int32_t pid; const bool hasPermission = PermissionCache::checkCallingPermission( String16(permission.c_str()), &pid, &uid); ALOGV("%s: Checking %s permission for pid %d uid %d: %s", __func__, permission.c_str(), pid, uid, hasPermission ? "granted" : "denied"); return hasPermission; } } // namespace const PermissionsProxy& PermissionsProxy::get() { static PermissionsProxyImpl sPermissionProxyImpl; return sPermissionProxyImpl; } } // namespace virtualcamera } // namespace companion } // namespace android Loading
services/camera/virtualcamera/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -54,6 +54,7 @@ cc_library_static { "util/EglProgram.cc", "util/EglSurfaceTexture.cc", "util/EglUtil.cc", "util/Permissions.cc" ], defaults: [ "libvirtualcamera_defaults", Loading
services/camera/virtualcamera/VirtualCameraService.cc +26 −2 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ #include "android/binder_auto_utils.h" #include "android/binder_libbinder.h" #include "binder/Status.h" #include "util/Permissions.h" #include "util/Util.h" using ::android::binder::Status; Loading @@ -54,6 +55,8 @@ Available commands: * enable_test_camera * disable_test_camera )"; constexpr char kCreateVirtualDevicePermission[] = "android.permission.CREATE_VIRTUAL_DEVICE"; ndk::ScopedAStatus validateConfiguration( const VirtualCameraConfiguration& configuration) { Loading @@ -79,17 +82,26 @@ ndk::ScopedAStatus validateConfiguration( } // namespace VirtualCameraService::VirtualCameraService( std::shared_ptr<VirtualCameraProvider> virtualCameraProvider) : mVirtualCameraProvider(virtualCameraProvider) { std::shared_ptr<VirtualCameraProvider> virtualCameraProvider, const PermissionsProxy& permissionProxy) : mVirtualCameraProvider(virtualCameraProvider), mPermissionProxy(permissionProxy) { } ndk::ScopedAStatus VirtualCameraService::registerCamera( const ::ndk::SpAIBinder& token, const VirtualCameraConfiguration& configuration, bool* _aidl_return) { if (!mPermissionProxy.checkCallingPermission(kCreateVirtualDevicePermission)) { ALOGE("%s: caller (pid %d, uid %d) doesn't hold %s permission", __func__, getpid(), getuid(), kCreateVirtualDevicePermission); return ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY); } if (_aidl_return == nullptr) { return ndk::ScopedAStatus::fromServiceSpecificError( Status::EX_ILLEGAL_ARGUMENT); } *_aidl_return = true; auto status = validateConfiguration(configuration); Loading Loading @@ -127,6 +139,12 @@ ndk::ScopedAStatus VirtualCameraService::registerCamera( ndk::ScopedAStatus VirtualCameraService::unregisterCamera( const ::ndk::SpAIBinder& token) { if (!mPermissionProxy.checkCallingPermission(kCreateVirtualDevicePermission)) { ALOGE("%s: caller (pid %d, uid %d) doesn't hold %s permission", __func__, getpid(), getuid(), kCreateVirtualDevicePermission); return ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY); } std::lock_guard lock(mLock); auto it = mTokenToCameraName.find(token); Loading @@ -145,6 +163,12 @@ ndk::ScopedAStatus VirtualCameraService::unregisterCamera( ndk::ScopedAStatus VirtualCameraService::getCameraId( const ::ndk::SpAIBinder& token, int32_t* _aidl_return) { if (!mPermissionProxy.checkCallingPermission(kCreateVirtualDevicePermission)) { ALOGE("%s: caller (pid %d, uid %d) doesn't hold %s permission", __func__, getpid(), getuid(), kCreateVirtualDevicePermission); return ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY); } if (_aidl_return == nullptr) { return ndk::ScopedAStatus::fromServiceSpecificError( Status::EX_ILLEGAL_ARGUMENT); Loading
services/camera/virtualcamera/VirtualCameraService.h +5 −1 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include "VirtualCameraDevice.h" #include "VirtualCameraProvider.h" #include "aidl/android/companion/virtualcamera/BnVirtualCameraService.h" #include "util/Permissions.h" namespace android { namespace companion { Loading @@ -34,7 +35,8 @@ class VirtualCameraService : public aidl::android::companion::virtualcamera::BnVirtualCameraService { public: VirtualCameraService( std::shared_ptr<VirtualCameraProvider> virtualCameraProvider); std::shared_ptr<VirtualCameraProvider> virtualCameraProvider, const PermissionsProxy& permissionProxy = PermissionsProxy::get()); // Register camera corresponding to the binder token. ndk::ScopedAStatus registerCamera( Loading Loading @@ -68,6 +70,8 @@ class VirtualCameraService std::shared_ptr<VirtualCameraProvider> mVirtualCameraProvider; const PermissionsProxy& mPermissionProxy; std::mutex mLock; struct BinderTokenHash { std::size_t operator()(const ::ndk::SpAIBinder& key) const { Loading
services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc +50 −2 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ #include "binder/Binder.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "util/Permissions.h" #include "utils/Errors.h" namespace android { Loading @@ -50,10 +51,13 @@ using ::testing::Ge; using ::testing::IsEmpty; using ::testing::IsNull; using ::testing::Not; using ::testing::Return; using ::testing::SizeIs; constexpr int kVgaWidth = 640; constexpr int kVgaHeight = 480; constexpr char kCreateVirtualDevicePermissions[] = "android.permission.CREATE_VIRTUAL_DEVICE"; const VirtualCameraConfiguration kEmptyVirtualCameraConfiguration; Loading @@ -76,6 +80,12 @@ class MockCameraProviderCallback : public BnCameraProviderCallback { (override)); }; class MockPermissionsProxy : public PermissionsProxy { public: MOCK_METHOD(bool, checkCallingPermission, (const std::string&), (const override)); }; class VirtualCameraServiceTest : public ::testing::Test { public: void SetUp() override { Loading @@ -87,8 +97,11 @@ class VirtualCameraServiceTest : public ::testing::Test { return ndk::ScopedAStatus::ok(); }); mCameraProvider->setCallback(mMockCameraProviderCallback); mCameraService = ndk::SharedRefBase::make<VirtualCameraService>(mCameraProvider); mCameraService = ndk::SharedRefBase::make<VirtualCameraService>( mCameraProvider, mMockPermissionsProxy); ON_CALL(mMockPermissionsProxy, checkCallingPermission) .WillByDefault(Return(true)); mDevNullFd = open("/dev/null", O_RDWR); ASSERT_THAT(mDevNullFd, Ge(0)); Loading Loading @@ -129,6 +142,7 @@ class VirtualCameraServiceTest : public ::testing::Test { std::shared_ptr<VirtualCameraProvider> mCameraProvider; std::shared_ptr<MockCameraProviderCallback> mMockCameraProviderCallback = ndk::SharedRefBase::make<MockCameraProviderCallback>(); MockPermissionsProxy mMockPermissionsProxy; sp<BBinder> mOwnerToken; ndk::SpAIBinder mNdkOwnerToken; Loading Loading @@ -242,6 +256,40 @@ TEST_F(VirtualCameraServiceTest, UnregisterCamera) { EXPECT_THAT(mCameraService->getCamera(mNdkOwnerToken), IsNull()); } TEST_F(VirtualCameraServiceTest, RegisterCameraWithoutPermissionFails) { bool aidlRet; EXPECT_CALL(mMockPermissionsProxy, checkCallingPermission(kCreateVirtualDevicePermissions)) .WillOnce(Return(false)); EXPECT_THAT(mCameraService ->registerCamera(mNdkOwnerToken, mVgaYUV420OnlyConfiguration, &aidlRet) .getExceptionCode(), Eq(EX_SECURITY)); } TEST_F(VirtualCameraServiceTest, UnregisterCameraWithoutPermissionFails) { EXPECT_CALL(mMockPermissionsProxy, checkCallingPermission(kCreateVirtualDevicePermissions)) .WillOnce(Return(false)); EXPECT_THAT( mCameraService->unregisterCamera(mNdkOwnerToken).getExceptionCode(), Eq(EX_SECURITY)); } TEST_F(VirtualCameraServiceTest, GetIdWithoutPermissionFails) { int32_t aidlRet; EXPECT_CALL(mMockPermissionsProxy, checkCallingPermission(kCreateVirtualDevicePermissions)) .WillOnce(Return(false)); EXPECT_THAT( mCameraService->getCameraId(mNdkOwnerToken, &aidlRet).getExceptionCode(), Eq(EX_SECURITY)); } TEST_F(VirtualCameraServiceTest, UnregisterCameraWithUnknownToken) { createCamera(); Loading
services/camera/virtualcamera/util/Permissions.cc 0 → 100644 +55 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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 "VirtualCameraPermissions" #include "Permissions.h" #include "binder/PermissionCache.h" #include "log/log.h" namespace android { namespace companion { namespace virtualcamera { namespace { class PermissionsProxyImpl : public PermissionsProxy { public: bool checkCallingPermission(const std::string& permission) const override; }; bool PermissionsProxyImpl::checkCallingPermission( const std::string& permission) const { int32_t uid; int32_t pid; const bool hasPermission = PermissionCache::checkCallingPermission( String16(permission.c_str()), &pid, &uid); ALOGV("%s: Checking %s permission for pid %d uid %d: %s", __func__, permission.c_str(), pid, uid, hasPermission ? "granted" : "denied"); return hasPermission; } } // namespace const PermissionsProxy& PermissionsProxy::get() { static PermissionsProxyImpl sPermissionProxyImpl; return sPermissionProxyImpl; } } // namespace virtualcamera } // namespace companion } // namespace android