blob: 74c97cc315ad408d783395364473a8bffd7bb1e6 [file] [log] [blame]
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +01001/*
Biswarup Pal6152a302023-12-19 12:44:09 +00002 * Copyright 2023 The Android Open Source Project
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +01003 *
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#include <cstdio>
18#include <memory>
19
20#include "VirtualCameraService.h"
21#include "aidl/android/companion/virtualcamera/BnVirtualCameraCallback.h"
22#include "aidl/android/companion/virtualcamera/VirtualCameraConfiguration.h"
23#include "aidl/android/hardware/camera/provider/BnCameraProviderCallback.h"
24#include "aidl/android/hardware/graphics/common/PixelFormat.h"
25#include "android/binder_auto_utils.h"
26#include "android/binder_interface_utils.h"
27#include "android/binder_libbinder.h"
28#include "android/binder_status.h"
29#include "binder/Binder.h"
30#include "gmock/gmock.h"
31#include "gtest/gtest.h"
Jan Sebechlebskyde6f16f2023-11-29 09:27:36 +010032#include "util/Permissions.h"
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010033#include "utils/Errors.h"
34
35namespace android {
36namespace companion {
37namespace virtualcamera {
38namespace {
39
40using ::aidl::android::companion::virtualcamera::BnVirtualCameraCallback;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010041using ::aidl::android::companion::virtualcamera::Format;
Biswarup Pal112458f2023-12-28 19:50:17 +000042using ::aidl::android::companion::virtualcamera::LensFacing;
Biswarup Pal6152a302023-12-19 12:44:09 +000043using ::aidl::android::companion::virtualcamera::SensorOrientation;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010044using ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration;
45using ::aidl::android::hardware::camera::common::CameraDeviceStatus;
46using ::aidl::android::hardware::camera::common::TorchModeStatus;
47using ::aidl::android::hardware::camera::provider::BnCameraProviderCallback;
48using ::aidl::android::hardware::graphics::common::PixelFormat;
49using ::aidl::android::view::Surface;
50using ::testing::_;
51using ::testing::Eq;
52using ::testing::Ge;
53using ::testing::IsEmpty;
54using ::testing::IsNull;
55using ::testing::Not;
Jan Sebechlebskyde6f16f2023-11-29 09:27:36 +010056using ::testing::Return;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010057using ::testing::SizeIs;
58
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010059constexpr int kVgaWidth = 640;
60constexpr int kVgaHeight = 480;
Biswarup Pal6152a302023-12-19 12:44:09 +000061constexpr int kMaxFps = 30;
Biswarup Pal112458f2023-12-28 19:50:17 +000062constexpr SensorOrientation kSensorOrientation =
63 SensorOrientation::ORIENTATION_0;
64constexpr LensFacing kLensFacing = LensFacing::FRONT;
Jan Sebechlebskyde6f16f2023-11-29 09:27:36 +010065constexpr char kCreateVirtualDevicePermissions[] =
66 "android.permission.CREATE_VIRTUAL_DEVICE";
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010067
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010068const VirtualCameraConfiguration kEmptyVirtualCameraConfiguration;
69
Biswarup Pal112458f2023-12-28 19:50:17 +000070VirtualCameraConfiguration createConfiguration(const int width, const int height,
71 const Format format,
72 const int maxFps) {
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010073 VirtualCameraConfiguration configuration;
Biswarup Pal6152a302023-12-19 12:44:09 +000074 configuration.supportedStreamConfigs.push_back({.width = width,
75 .height = height,
76 .pixelFormat = format,
77 .maxFps = maxFps});
Biswarup Pal112458f2023-12-28 19:50:17 +000078 configuration.sensorOrientation = kSensorOrientation;
79 configuration.lensFacing = kLensFacing;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010080 return configuration;
81}
82
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010083class MockCameraProviderCallback : public BnCameraProviderCallback {
84 public:
85 MOCK_METHOD(ndk::ScopedAStatus, cameraDeviceStatusChange,
86 (const std::string&, CameraDeviceStatus), (override));
87 MOCK_METHOD(ndk::ScopedAStatus, torchModeStatusChange,
88 (const std::string&, TorchModeStatus), (override));
89 MOCK_METHOD(ndk::ScopedAStatus, physicalCameraDeviceStatusChange,
90 (const std::string&, const std::string&, CameraDeviceStatus),
91 (override));
92};
93
Jan Sebechlebskyde6f16f2023-11-29 09:27:36 +010094class MockPermissionsProxy : public PermissionsProxy {
95 public:
96 MOCK_METHOD(bool, checkCallingPermission, (const std::string&),
97 (const override));
98};
99
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100100class VirtualCameraServiceTest : public ::testing::Test {
101 public:
102 void SetUp() override {
103 mCameraProvider = ndk::SharedRefBase::make<VirtualCameraProvider>();
104 mMockCameraProviderCallback =
105 ndk::SharedRefBase::make<MockCameraProviderCallback>();
106 ON_CALL(*mMockCameraProviderCallback, cameraDeviceStatusChange)
107 .WillByDefault([](const std::string&, CameraDeviceStatus) {
108 return ndk::ScopedAStatus::ok();
109 });
110 mCameraProvider->setCallback(mMockCameraProviderCallback);
Jan Sebechlebskyde6f16f2023-11-29 09:27:36 +0100111 mCameraService = ndk::SharedRefBase::make<VirtualCameraService>(
112 mCameraProvider, mMockPermissionsProxy);
113
114 ON_CALL(mMockPermissionsProxy, checkCallingPermission)
115 .WillByDefault(Return(true));
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100116
117 mDevNullFd = open("/dev/null", O_RDWR);
118 ASSERT_THAT(mDevNullFd, Ge(0));
119 }
120
121 void createCamera() {
122 mOwnerToken = sp<BBinder>::make();
123 mNdkOwnerToken.set(AIBinder_fromPlatformBinder(mOwnerToken));
124 bool aidlRet;
125
126 ASSERT_TRUE(mCameraService
127 ->registerCamera(mNdkOwnerToken,
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100128 mVgaYUV420OnlyConfiguration, &aidlRet)
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100129 .isOk());
130 ASSERT_TRUE(aidlRet);
131 }
132
133 void TearDown() override {
134 close(mDevNullFd);
135 }
136
137 void execute_shell_command(const std::string cmd) {
138 std::array<const char*, 1> args{cmd.data()};
139 ASSERT_THAT(
140 mCameraService->handleShellCommand(mDevNullFd, mDevNullFd, mDevNullFd,
141 args.data(), args.size()),
142 Eq(NO_ERROR));
143 }
144
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100145 std::vector<std::string> getCameraIds() {
146 std::vector<std::string> cameraIds;
147 EXPECT_TRUE(mCameraProvider->getCameraIdList(&cameraIds).isOk());
148 return cameraIds;
149 }
150
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100151 protected:
152 std::shared_ptr<VirtualCameraService> mCameraService;
153 std::shared_ptr<VirtualCameraProvider> mCameraProvider;
154 std::shared_ptr<MockCameraProviderCallback> mMockCameraProviderCallback =
155 ndk::SharedRefBase::make<MockCameraProviderCallback>();
Jan Sebechlebskyde6f16f2023-11-29 09:27:36 +0100156 MockPermissionsProxy mMockPermissionsProxy;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100157
158 sp<BBinder> mOwnerToken;
159 ndk::SpAIBinder mNdkOwnerToken;
160
161 int mDevNullFd;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100162
163 VirtualCameraConfiguration mVgaYUV420OnlyConfiguration =
Biswarup Pal112458f2023-12-28 19:50:17 +0000164 createConfiguration(kVgaWidth, kVgaHeight, Format::YUV_420_888, kMaxFps);
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100165};
166
Jan Sebechlebsky042d1fb2023-12-12 16:37:00 +0100167TEST_F(VirtualCameraServiceTest, RegisterCameraWithYuvInputSucceeds) {
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100168 sp<BBinder> token = sp<BBinder>::make();
169 ndk::SpAIBinder ndkToken(AIBinder_fromPlatformBinder(token));
170 bool aidlRet;
171
172 ASSERT_TRUE(
173 mCameraService
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100174 ->registerCamera(ndkToken, mVgaYUV420OnlyConfiguration, &aidlRet)
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100175 .isOk());
176
177 EXPECT_TRUE(aidlRet);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100178 EXPECT_THAT(getCameraIds(), SizeIs(1));
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100179}
180
Jan Sebechlebsky042d1fb2023-12-12 16:37:00 +0100181TEST_F(VirtualCameraServiceTest, RegisterCameraWithRgbaInputSucceeds) {
182 sp<BBinder> token = sp<BBinder>::make();
183 ndk::SpAIBinder ndkToken(AIBinder_fromPlatformBinder(token));
184 bool aidlRet;
185
186 VirtualCameraConfiguration config =
Biswarup Pal112458f2023-12-28 19:50:17 +0000187 createConfiguration(kVgaWidth, kVgaHeight, Format::RGBA_8888, kMaxFps);
Jan Sebechlebsky042d1fb2023-12-12 16:37:00 +0100188
189 ASSERT_TRUE(mCameraService->registerCamera(ndkToken, config, &aidlRet).isOk());
190
191 EXPECT_TRUE(aidlRet);
192 EXPECT_THAT(getCameraIds(), SizeIs(1));
193}
194
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100195TEST_F(VirtualCameraServiceTest, RegisterCameraTwiceSecondReturnsFalse) {
196 createCamera();
197 bool aidlRet;
198
199 ASSERT_TRUE(mCameraService
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100200 ->registerCamera(mNdkOwnerToken, mVgaYUV420OnlyConfiguration,
201 &aidlRet)
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100202 .isOk());
203 EXPECT_FALSE(aidlRet);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100204 EXPECT_THAT(getCameraIds(), SizeIs(1));
205}
206
207TEST_F(VirtualCameraServiceTest, EmptyConfigurationFails) {
208 bool aidlRet;
209
210 ASSERT_FALSE(mCameraService
211 ->registerCamera(mNdkOwnerToken,
212 kEmptyVirtualCameraConfiguration, &aidlRet)
213 .isOk());
214 EXPECT_FALSE(aidlRet);
215 EXPECT_THAT(getCameraIds(), IsEmpty());
216}
217
218TEST_F(VirtualCameraServiceTest, ConfigurationWithUnsupportedPixelFormatFails) {
219 bool aidlRet;
220
221 VirtualCameraConfiguration config =
Biswarup Pal112458f2023-12-28 19:50:17 +0000222 createConfiguration(kVgaWidth, kVgaHeight, Format::UNKNOWN, kMaxFps);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100223
224 ASSERT_FALSE(
225 mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
226 EXPECT_FALSE(aidlRet);
227 EXPECT_THAT(getCameraIds(), IsEmpty());
228}
229
230TEST_F(VirtualCameraServiceTest, ConfigurationWithTooHighResFails) {
231 bool aidlRet;
232 VirtualCameraConfiguration config =
Biswarup Pal112458f2023-12-28 19:50:17 +0000233 createConfiguration(1000000, 1000000, Format::YUV_420_888, kMaxFps);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100234
235 ASSERT_FALSE(
236 mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
237 EXPECT_FALSE(aidlRet);
238 EXPECT_THAT(getCameraIds(), IsEmpty());
239}
240
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100241TEST_F(VirtualCameraServiceTest, ConfigurationWithNegativeResolutionFails) {
242 bool aidlRet;
243 VirtualCameraConfiguration config =
Biswarup Pal112458f2023-12-28 19:50:17 +0000244 createConfiguration(-1, kVgaHeight, Format::YUV_420_888, kMaxFps);
Biswarup Pal6152a302023-12-19 12:44:09 +0000245
246 ASSERT_FALSE(
247 mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
248 EXPECT_FALSE(aidlRet);
249 EXPECT_THAT(getCameraIds(), IsEmpty());
250}
251
252TEST_F(VirtualCameraServiceTest, ConfigurationWithTooLowMaxFpsFails) {
253 bool aidlRet;
254 VirtualCameraConfiguration config =
Biswarup Pal112458f2023-12-28 19:50:17 +0000255 createConfiguration(kVgaWidth, kVgaHeight, Format::YUV_420_888, 0);
Biswarup Pal6152a302023-12-19 12:44:09 +0000256
257 ASSERT_FALSE(
258 mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
259 EXPECT_FALSE(aidlRet);
260 EXPECT_THAT(getCameraIds(), IsEmpty());
261}
262
263TEST_F(VirtualCameraServiceTest, ConfigurationWithTooHighMaxFpsFails) {
264 bool aidlRet;
265 VirtualCameraConfiguration config =
Biswarup Pal112458f2023-12-28 19:50:17 +0000266 createConfiguration(kVgaWidth, kVgaHeight, Format::YUV_420_888, 90);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100267
268 ASSERT_FALSE(
269 mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
270 EXPECT_FALSE(aidlRet);
271 EXPECT_THAT(getCameraIds(), IsEmpty());
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100272}
273
274TEST_F(VirtualCameraServiceTest, GetCamera) {
275 createCamera();
276
277 EXPECT_THAT(mCameraService->getCamera(mNdkOwnerToken), Not(IsNull()));
278
279 sp<BBinder> otherToken = sp<BBinder>::make();
280 EXPECT_THAT(mCameraService->getCamera(
281 ndk::SpAIBinder(AIBinder_fromPlatformBinder(otherToken))),
282 IsNull());
283}
284
285TEST_F(VirtualCameraServiceTest, UnregisterCamera) {
286 createCamera();
287
288 EXPECT_THAT(mCameraService->getCamera(mNdkOwnerToken), Not(IsNull()));
289
290 mCameraService->unregisterCamera(mNdkOwnerToken);
291
292 EXPECT_THAT(mCameraService->getCamera(mNdkOwnerToken), IsNull());
293}
294
Jan Sebechlebskyde6f16f2023-11-29 09:27:36 +0100295TEST_F(VirtualCameraServiceTest, RegisterCameraWithoutPermissionFails) {
296 bool aidlRet;
297 EXPECT_CALL(mMockPermissionsProxy,
298 checkCallingPermission(kCreateVirtualDevicePermissions))
299 .WillOnce(Return(false));
300
301 EXPECT_THAT(mCameraService
302 ->registerCamera(mNdkOwnerToken, mVgaYUV420OnlyConfiguration,
303 &aidlRet)
304 .getExceptionCode(),
305 Eq(EX_SECURITY));
306}
307
308TEST_F(VirtualCameraServiceTest, UnregisterCameraWithoutPermissionFails) {
309 EXPECT_CALL(mMockPermissionsProxy,
310 checkCallingPermission(kCreateVirtualDevicePermissions))
311 .WillOnce(Return(false));
312
313 EXPECT_THAT(
314 mCameraService->unregisterCamera(mNdkOwnerToken).getExceptionCode(),
315 Eq(EX_SECURITY));
316}
317
318TEST_F(VirtualCameraServiceTest, GetIdWithoutPermissionFails) {
319 int32_t aidlRet;
320 EXPECT_CALL(mMockPermissionsProxy,
321 checkCallingPermission(kCreateVirtualDevicePermissions))
322 .WillOnce(Return(false));
323
324 EXPECT_THAT(
325 mCameraService->getCameraId(mNdkOwnerToken, &aidlRet).getExceptionCode(),
326 Eq(EX_SECURITY));
327}
328
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100329TEST_F(VirtualCameraServiceTest, UnregisterCameraWithUnknownToken) {
330 createCamera();
331
332 EXPECT_THAT(mCameraService->getCamera(mNdkOwnerToken), Not(IsNull()));
333
334 auto otherToken = sp<BBinder>::make();
335 ndk::SpAIBinder ndkOtherToken(AIBinder_fromPlatformBinder(otherToken));
336 mCameraService->unregisterCamera(ndkOtherToken);
337
338 EXPECT_THAT(mCameraService->getCamera(mNdkOwnerToken), Not(IsNull()));
339}
340
341TEST_F(VirtualCameraServiceTest, ShellCmdWithNullArgs) {
342 EXPECT_EQ(mCameraService->handleShellCommand(
343 /*in=*/mDevNullFd, /*out=*/mDevNullFd, /*err=*/mDevNullFd,
344 /*args=*/nullptr, /*numArgs=*/1),
345 STATUS_BAD_VALUE);
346
347 std::array<const char*, 1> args{nullptr};
348 EXPECT_EQ(mCameraService->handleShellCommand(
349 /*in=*/mDevNullFd, /*out=*/mDevNullFd, /*err=*/mDevNullFd,
350 args.data(), /*numArgs=*/1),
351 STATUS_BAD_VALUE);
352}
353
Jan Sebechlebsky76d7e212023-11-28 14:10:25 +0100354TEST_F(VirtualCameraServiceTest, ShellCmdWithNoArgs) {
355 EXPECT_EQ(mCameraService->handleShellCommand(
356 /*in=*/mDevNullFd, /*out=*/mDevNullFd, /*err=*/mDevNullFd,
357 /*args=*/nullptr, /*numArgs=*/0),
358 STATUS_OK);
359}
360
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100361TEST_F(VirtualCameraServiceTest, TestCameraShellCmd) {
362 execute_shell_command("enable_test_camera");
363
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100364 std::vector<std::string> cameraIdsAfterEnable = getCameraIds();
365 EXPECT_THAT(cameraIdsAfterEnable, SizeIs(1));
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100366
367 execute_shell_command("disable_test_camera");
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100368
369 std::vector<std::string> cameraIdsAfterDisable = getCameraIds();
370 EXPECT_THAT(cameraIdsAfterDisable, IsEmpty());
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100371}
372
373} // namespace
374} // namespace virtualcamera
375} // namespace companion
376} // namespace android