blob: 12a09f51250f876598551ad7f0db49a7150bfc35 [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
Marvin Ramina8196132024-03-15 15:55:22 +0000145 void execute_shell_command(const std::string cmd, const std::string cameraId) {
146 std::array<const char*, 2> args{cmd.data(), cameraId.data()};
147 ASSERT_THAT(
148 mCameraService->handleShellCommand(mDevNullFd, mDevNullFd, mDevNullFd,
149 args.data(), args.size()),
150 Eq(NO_ERROR));
151 }
152
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100153 std::vector<std::string> getCameraIds() {
154 std::vector<std::string> cameraIds;
155 EXPECT_TRUE(mCameraProvider->getCameraIdList(&cameraIds).isOk());
156 return cameraIds;
157 }
158
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100159 protected:
160 std::shared_ptr<VirtualCameraService> mCameraService;
161 std::shared_ptr<VirtualCameraProvider> mCameraProvider;
162 std::shared_ptr<MockCameraProviderCallback> mMockCameraProviderCallback =
163 ndk::SharedRefBase::make<MockCameraProviderCallback>();
Jan Sebechlebskyde6f16f2023-11-29 09:27:36 +0100164 MockPermissionsProxy mMockPermissionsProxy;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100165
166 sp<BBinder> mOwnerToken;
167 ndk::SpAIBinder mNdkOwnerToken;
168
169 int mDevNullFd;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100170
171 VirtualCameraConfiguration mVgaYUV420OnlyConfiguration =
Biswarup Pal112458f2023-12-28 19:50:17 +0000172 createConfiguration(kVgaWidth, kVgaHeight, Format::YUV_420_888, kMaxFps);
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100173};
174
Jan Sebechlebsky042d1fb2023-12-12 16:37:00 +0100175TEST_F(VirtualCameraServiceTest, RegisterCameraWithYuvInputSucceeds) {
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100176 sp<BBinder> token = sp<BBinder>::make();
177 ndk::SpAIBinder ndkToken(AIBinder_fromPlatformBinder(token));
178 bool aidlRet;
179
180 ASSERT_TRUE(
181 mCameraService
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100182 ->registerCamera(ndkToken, mVgaYUV420OnlyConfiguration, &aidlRet)
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100183 .isOk());
184
185 EXPECT_TRUE(aidlRet);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100186 EXPECT_THAT(getCameraIds(), SizeIs(1));
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100187}
188
Jan Sebechlebsky042d1fb2023-12-12 16:37:00 +0100189TEST_F(VirtualCameraServiceTest, RegisterCameraWithRgbaInputSucceeds) {
190 sp<BBinder> token = sp<BBinder>::make();
191 ndk::SpAIBinder ndkToken(AIBinder_fromPlatformBinder(token));
192 bool aidlRet;
193
194 VirtualCameraConfiguration config =
Biswarup Pal112458f2023-12-28 19:50:17 +0000195 createConfiguration(kVgaWidth, kVgaHeight, Format::RGBA_8888, kMaxFps);
Jan Sebechlebsky042d1fb2023-12-12 16:37:00 +0100196
197 ASSERT_TRUE(mCameraService->registerCamera(ndkToken, config, &aidlRet).isOk());
198
199 EXPECT_TRUE(aidlRet);
200 EXPECT_THAT(getCameraIds(), SizeIs(1));
201}
202
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100203TEST_F(VirtualCameraServiceTest, RegisterCameraTwiceSecondReturnsFalse) {
204 createCamera();
205 bool aidlRet;
206
207 ASSERT_TRUE(mCameraService
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100208 ->registerCamera(mNdkOwnerToken, mVgaYUV420OnlyConfiguration,
209 &aidlRet)
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100210 .isOk());
211 EXPECT_FALSE(aidlRet);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100212 EXPECT_THAT(getCameraIds(), SizeIs(1));
213}
214
215TEST_F(VirtualCameraServiceTest, EmptyConfigurationFails) {
216 bool aidlRet;
217
218 ASSERT_FALSE(mCameraService
219 ->registerCamera(mNdkOwnerToken,
220 kEmptyVirtualCameraConfiguration, &aidlRet)
221 .isOk());
222 EXPECT_FALSE(aidlRet);
223 EXPECT_THAT(getCameraIds(), IsEmpty());
224}
225
226TEST_F(VirtualCameraServiceTest, ConfigurationWithUnsupportedPixelFormatFails) {
227 bool aidlRet;
228
229 VirtualCameraConfiguration config =
Biswarup Pal112458f2023-12-28 19:50:17 +0000230 createConfiguration(kVgaWidth, kVgaHeight, Format::UNKNOWN, kMaxFps);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100231
232 ASSERT_FALSE(
233 mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
234 EXPECT_FALSE(aidlRet);
235 EXPECT_THAT(getCameraIds(), IsEmpty());
236}
237
238TEST_F(VirtualCameraServiceTest, ConfigurationWithTooHighResFails) {
239 bool aidlRet;
240 VirtualCameraConfiguration config =
Biswarup Pal112458f2023-12-28 19:50:17 +0000241 createConfiguration(1000000, 1000000, Format::YUV_420_888, kMaxFps);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100242
243 ASSERT_FALSE(
244 mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
245 EXPECT_FALSE(aidlRet);
246 EXPECT_THAT(getCameraIds(), IsEmpty());
247}
248
249TEST_F(VirtualCameraServiceTest, ConfigurationWithUnalignedResolutionFails) {
250 bool aidlRet;
Biswarup Pal112458f2023-12-28 19:50:17 +0000251 VirtualCameraConfiguration config =
252 createConfiguration(641, 481, Format::YUV_420_888, kMaxFps);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100253
254 ASSERT_FALSE(
255 mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
256 EXPECT_FALSE(aidlRet);
257 EXPECT_THAT(getCameraIds(), IsEmpty());
258}
259
260TEST_F(VirtualCameraServiceTest, ConfigurationWithNegativeResolutionFails) {
261 bool aidlRet;
262 VirtualCameraConfiguration config =
Biswarup Pal112458f2023-12-28 19:50:17 +0000263 createConfiguration(-1, kVgaHeight, Format::YUV_420_888, kMaxFps);
Biswarup Pal6152a302023-12-19 12:44:09 +0000264
265 ASSERT_FALSE(
266 mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
267 EXPECT_FALSE(aidlRet);
268 EXPECT_THAT(getCameraIds(), IsEmpty());
269}
270
271TEST_F(VirtualCameraServiceTest, ConfigurationWithTooLowMaxFpsFails) {
272 bool aidlRet;
273 VirtualCameraConfiguration config =
Biswarup Pal112458f2023-12-28 19:50:17 +0000274 createConfiguration(kVgaWidth, kVgaHeight, Format::YUV_420_888, 0);
Biswarup Pal6152a302023-12-19 12:44:09 +0000275
276 ASSERT_FALSE(
277 mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
278 EXPECT_FALSE(aidlRet);
279 EXPECT_THAT(getCameraIds(), IsEmpty());
280}
281
282TEST_F(VirtualCameraServiceTest, ConfigurationWithTooHighMaxFpsFails) {
283 bool aidlRet;
284 VirtualCameraConfiguration config =
Biswarup Pal112458f2023-12-28 19:50:17 +0000285 createConfiguration(kVgaWidth, kVgaHeight, Format::YUV_420_888, 90);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100286
287 ASSERT_FALSE(
288 mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
289 EXPECT_FALSE(aidlRet);
290 EXPECT_THAT(getCameraIds(), IsEmpty());
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100291}
292
293TEST_F(VirtualCameraServiceTest, GetCamera) {
294 createCamera();
295
296 EXPECT_THAT(mCameraService->getCamera(mNdkOwnerToken), Not(IsNull()));
297
298 sp<BBinder> otherToken = sp<BBinder>::make();
299 EXPECT_THAT(mCameraService->getCamera(
300 ndk::SpAIBinder(AIBinder_fromPlatformBinder(otherToken))),
301 IsNull());
302}
303
304TEST_F(VirtualCameraServiceTest, UnregisterCamera) {
305 createCamera();
306
307 EXPECT_THAT(mCameraService->getCamera(mNdkOwnerToken), Not(IsNull()));
308
309 mCameraService->unregisterCamera(mNdkOwnerToken);
310
311 EXPECT_THAT(mCameraService->getCamera(mNdkOwnerToken), IsNull());
312}
313
Jan Sebechlebskyde6f16f2023-11-29 09:27:36 +0100314TEST_F(VirtualCameraServiceTest, RegisterCameraWithoutPermissionFails) {
315 bool aidlRet;
316 EXPECT_CALL(mMockPermissionsProxy,
317 checkCallingPermission(kCreateVirtualDevicePermissions))
318 .WillOnce(Return(false));
319
320 EXPECT_THAT(mCameraService
321 ->registerCamera(mNdkOwnerToken, mVgaYUV420OnlyConfiguration,
322 &aidlRet)
323 .getExceptionCode(),
324 Eq(EX_SECURITY));
325}
326
327TEST_F(VirtualCameraServiceTest, UnregisterCameraWithoutPermissionFails) {
328 EXPECT_CALL(mMockPermissionsProxy,
329 checkCallingPermission(kCreateVirtualDevicePermissions))
330 .WillOnce(Return(false));
331
332 EXPECT_THAT(
333 mCameraService->unregisterCamera(mNdkOwnerToken).getExceptionCode(),
334 Eq(EX_SECURITY));
335}
336
337TEST_F(VirtualCameraServiceTest, GetIdWithoutPermissionFails) {
338 int32_t aidlRet;
339 EXPECT_CALL(mMockPermissionsProxy,
340 checkCallingPermission(kCreateVirtualDevicePermissions))
341 .WillOnce(Return(false));
342
343 EXPECT_THAT(
344 mCameraService->getCameraId(mNdkOwnerToken, &aidlRet).getExceptionCode(),
345 Eq(EX_SECURITY));
346}
347
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100348TEST_F(VirtualCameraServiceTest, UnregisterCameraWithUnknownToken) {
349 createCamera();
350
351 EXPECT_THAT(mCameraService->getCamera(mNdkOwnerToken), Not(IsNull()));
352
353 auto otherToken = sp<BBinder>::make();
354 ndk::SpAIBinder ndkOtherToken(AIBinder_fromPlatformBinder(otherToken));
355 mCameraService->unregisterCamera(ndkOtherToken);
356
357 EXPECT_THAT(mCameraService->getCamera(mNdkOwnerToken), Not(IsNull()));
358}
359
360TEST_F(VirtualCameraServiceTest, ShellCmdWithNullArgs) {
361 EXPECT_EQ(mCameraService->handleShellCommand(
362 /*in=*/mDevNullFd, /*out=*/mDevNullFd, /*err=*/mDevNullFd,
363 /*args=*/nullptr, /*numArgs=*/1),
364 STATUS_BAD_VALUE);
365
366 std::array<const char*, 1> args{nullptr};
367 EXPECT_EQ(mCameraService->handleShellCommand(
368 /*in=*/mDevNullFd, /*out=*/mDevNullFd, /*err=*/mDevNullFd,
369 args.data(), /*numArgs=*/1),
370 STATUS_BAD_VALUE);
371}
372
Jan Sebechlebsky76d7e212023-11-28 14:10:25 +0100373TEST_F(VirtualCameraServiceTest, ShellCmdWithNoArgs) {
374 EXPECT_EQ(mCameraService->handleShellCommand(
375 /*in=*/mDevNullFd, /*out=*/mDevNullFd, /*err=*/mDevNullFd,
376 /*args=*/nullptr, /*numArgs=*/0),
377 STATUS_OK);
378}
379
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100380TEST_F(VirtualCameraServiceTest, TestCameraShellCmd) {
381 execute_shell_command("enable_test_camera");
382
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100383 std::vector<std::string> cameraIdsAfterEnable = getCameraIds();
384 EXPECT_THAT(cameraIdsAfterEnable, SizeIs(1));
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100385
386 execute_shell_command("disable_test_camera");
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100387
388 std::vector<std::string> cameraIdsAfterDisable = getCameraIds();
389 EXPECT_THAT(cameraIdsAfterDisable, IsEmpty());
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100390}
391
Marvin Ramina8196132024-03-15 15:55:22 +0000392TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithId) {
393 execute_shell_command("enable_test_camera", "12345");
394
395 std::vector<std::string> cameraIdsAfterEnable = getCameraIds();
396 EXPECT_THAT(cameraIdsAfterEnable, SizeIs(1));
397
398 execute_shell_command("disable_test_camera");
399
400 std::vector<std::string> cameraIdsAfterDisable = getCameraIds();
401 EXPECT_THAT(cameraIdsAfterDisable, IsEmpty());
402}
403
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100404} // namespace
405} // namespace virtualcamera
406} // namespace companion
407} // namespace android