blob: d530d91df0490621c2936a00e5dc67cd8bfa4768 [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
Jan Sebechlebsky685ba1e2024-03-25 10:33:09 +010017#include <algorithm>
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010018#include <cstdio>
Jan Sebechlebsky685ba1e2024-03-25 10:33:09 +010019#include <iterator>
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010020#include <memory>
Jan Sebechlebsky685ba1e2024-03-25 10:33:09 +010021#include <regex>
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010022
23#include "VirtualCameraService.h"
24#include "aidl/android/companion/virtualcamera/BnVirtualCameraCallback.h"
25#include "aidl/android/companion/virtualcamera/VirtualCameraConfiguration.h"
26#include "aidl/android/hardware/camera/provider/BnCameraProviderCallback.h"
27#include "aidl/android/hardware/graphics/common/PixelFormat.h"
28#include "android/binder_auto_utils.h"
29#include "android/binder_interface_utils.h"
30#include "android/binder_libbinder.h"
31#include "android/binder_status.h"
32#include "binder/Binder.h"
33#include "gmock/gmock.h"
34#include "gtest/gtest.h"
Jan Sebechlebskyde6f16f2023-11-29 09:27:36 +010035#include "util/Permissions.h"
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010036#include "utils/Errors.h"
37
38namespace android {
39namespace companion {
40namespace virtualcamera {
41namespace {
42
43using ::aidl::android::companion::virtualcamera::BnVirtualCameraCallback;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010044using ::aidl::android::companion::virtualcamera::Format;
Biswarup Pal112458f2023-12-28 19:50:17 +000045using ::aidl::android::companion::virtualcamera::LensFacing;
Biswarup Pal6152a302023-12-19 12:44:09 +000046using ::aidl::android::companion::virtualcamera::SensorOrientation;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010047using ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration;
48using ::aidl::android::hardware::camera::common::CameraDeviceStatus;
49using ::aidl::android::hardware::camera::common::TorchModeStatus;
50using ::aidl::android::hardware::camera::provider::BnCameraProviderCallback;
51using ::aidl::android::hardware::graphics::common::PixelFormat;
52using ::aidl::android::view::Surface;
53using ::testing::_;
Jan Sebechlebsky685ba1e2024-03-25 10:33:09 +010054using ::testing::ElementsAre;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010055using ::testing::Eq;
56using ::testing::Ge;
57using ::testing::IsEmpty;
58using ::testing::IsNull;
59using ::testing::Not;
Jan Sebechlebskyde6f16f2023-11-29 09:27:36 +010060using ::testing::Return;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010061using ::testing::SizeIs;
62
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010063constexpr int kVgaWidth = 640;
64constexpr int kVgaHeight = 480;
Biswarup Pal6152a302023-12-19 12:44:09 +000065constexpr int kMaxFps = 30;
Biswarup Pal112458f2023-12-28 19:50:17 +000066constexpr SensorOrientation kSensorOrientation =
67 SensorOrientation::ORIENTATION_0;
68constexpr LensFacing kLensFacing = LensFacing::FRONT;
Jan Sebechlebskyde6f16f2023-11-29 09:27:36 +010069constexpr char kCreateVirtualDevicePermissions[] =
70 "android.permission.CREATE_VIRTUAL_DEVICE";
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010071
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010072const VirtualCameraConfiguration kEmptyVirtualCameraConfiguration;
73
Biswarup Pal112458f2023-12-28 19:50:17 +000074VirtualCameraConfiguration createConfiguration(const int width, const int height,
75 const Format format,
76 const int maxFps) {
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010077 VirtualCameraConfiguration configuration;
Biswarup Pal6152a302023-12-19 12:44:09 +000078 configuration.supportedStreamConfigs.push_back({.width = width,
79 .height = height,
80 .pixelFormat = format,
81 .maxFps = maxFps});
Biswarup Pal112458f2023-12-28 19:50:17 +000082 configuration.sensorOrientation = kSensorOrientation;
83 configuration.lensFacing = kLensFacing;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010084 return configuration;
85}
86
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010087class MockCameraProviderCallback : public BnCameraProviderCallback {
88 public:
89 MOCK_METHOD(ndk::ScopedAStatus, cameraDeviceStatusChange,
90 (const std::string&, CameraDeviceStatus), (override));
91 MOCK_METHOD(ndk::ScopedAStatus, torchModeStatusChange,
92 (const std::string&, TorchModeStatus), (override));
93 MOCK_METHOD(ndk::ScopedAStatus, physicalCameraDeviceStatusChange,
94 (const std::string&, const std::string&, CameraDeviceStatus),
95 (override));
96};
97
Jan Sebechlebskyde6f16f2023-11-29 09:27:36 +010098class MockPermissionsProxy : public PermissionsProxy {
99 public:
100 MOCK_METHOD(bool, checkCallingPermission, (const std::string&),
101 (const override));
102};
103
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100104class VirtualCameraServiceTest : public ::testing::Test {
105 public:
106 void SetUp() override {
107 mCameraProvider = ndk::SharedRefBase::make<VirtualCameraProvider>();
108 mMockCameraProviderCallback =
109 ndk::SharedRefBase::make<MockCameraProviderCallback>();
110 ON_CALL(*mMockCameraProviderCallback, cameraDeviceStatusChange)
111 .WillByDefault([](const std::string&, CameraDeviceStatus) {
112 return ndk::ScopedAStatus::ok();
113 });
114 mCameraProvider->setCallback(mMockCameraProviderCallback);
Jan Sebechlebskyde6f16f2023-11-29 09:27:36 +0100115 mCameraService = ndk::SharedRefBase::make<VirtualCameraService>(
116 mCameraProvider, mMockPermissionsProxy);
117
118 ON_CALL(mMockPermissionsProxy, checkCallingPermission)
119 .WillByDefault(Return(true));
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100120
121 mDevNullFd = open("/dev/null", O_RDWR);
122 ASSERT_THAT(mDevNullFd, Ge(0));
123 }
124
125 void createCamera() {
126 mOwnerToken = sp<BBinder>::make();
127 mNdkOwnerToken.set(AIBinder_fromPlatformBinder(mOwnerToken));
128 bool aidlRet;
129
130 ASSERT_TRUE(mCameraService
131 ->registerCamera(mNdkOwnerToken,
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100132 mVgaYUV420OnlyConfiguration, &aidlRet)
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100133 .isOk());
134 ASSERT_TRUE(aidlRet);
135 }
136
137 void TearDown() override {
138 close(mDevNullFd);
139 }
140
Jan Sebechlebsky685ba1e2024-03-25 10:33:09 +0100141 void execute_shell_command(const std::string& cmd) {
142 const static std::regex whitespaceRegex("\\s+");
143 std::vector<std::string> tokens;
144 std::copy_if(
145 std::sregex_token_iterator(cmd.begin(), cmd.end(), whitespaceRegex, -1),
146 std::sregex_token_iterator(), std::back_inserter(tokens),
147 [](const std::string& token) { return !token.empty(); });
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100148
Jan Sebechlebsky685ba1e2024-03-25 10:33:09 +0100149 std::vector<const char*> argv;
150 argv.reserve(tokens.size());
151 std::transform(tokens.begin(), tokens.end(), std::back_inserter(argv),
152 [](const std::string& str) { return str.c_str(); });
153
Marvin Ramina8196132024-03-15 15:55:22 +0000154 ASSERT_THAT(
155 mCameraService->handleShellCommand(mDevNullFd, mDevNullFd, mDevNullFd,
Jan Sebechlebsky685ba1e2024-03-25 10:33:09 +0100156 argv.data(), argv.size()),
Marvin Ramina8196132024-03-15 15:55:22 +0000157 Eq(NO_ERROR));
158 }
159
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100160 std::vector<std::string> getCameraIds() {
161 std::vector<std::string> cameraIds;
162 EXPECT_TRUE(mCameraProvider->getCameraIdList(&cameraIds).isOk());
163 return cameraIds;
164 }
165
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100166 protected:
167 std::shared_ptr<VirtualCameraService> mCameraService;
168 std::shared_ptr<VirtualCameraProvider> mCameraProvider;
169 std::shared_ptr<MockCameraProviderCallback> mMockCameraProviderCallback =
170 ndk::SharedRefBase::make<MockCameraProviderCallback>();
Jan Sebechlebskyde6f16f2023-11-29 09:27:36 +0100171 MockPermissionsProxy mMockPermissionsProxy;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100172
173 sp<BBinder> mOwnerToken;
174 ndk::SpAIBinder mNdkOwnerToken;
175
176 int mDevNullFd;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100177
178 VirtualCameraConfiguration mVgaYUV420OnlyConfiguration =
Biswarup Pal112458f2023-12-28 19:50:17 +0000179 createConfiguration(kVgaWidth, kVgaHeight, Format::YUV_420_888, kMaxFps);
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100180};
181
Jan Sebechlebsky042d1fb2023-12-12 16:37:00 +0100182TEST_F(VirtualCameraServiceTest, RegisterCameraWithYuvInputSucceeds) {
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100183 sp<BBinder> token = sp<BBinder>::make();
184 ndk::SpAIBinder ndkToken(AIBinder_fromPlatformBinder(token));
185 bool aidlRet;
186
187 ASSERT_TRUE(
188 mCameraService
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100189 ->registerCamera(ndkToken, mVgaYUV420OnlyConfiguration, &aidlRet)
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100190 .isOk());
191
192 EXPECT_TRUE(aidlRet);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100193 EXPECT_THAT(getCameraIds(), SizeIs(1));
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100194}
195
Jan Sebechlebsky042d1fb2023-12-12 16:37:00 +0100196TEST_F(VirtualCameraServiceTest, RegisterCameraWithRgbaInputSucceeds) {
197 sp<BBinder> token = sp<BBinder>::make();
198 ndk::SpAIBinder ndkToken(AIBinder_fromPlatformBinder(token));
199 bool aidlRet;
200
201 VirtualCameraConfiguration config =
Biswarup Pal112458f2023-12-28 19:50:17 +0000202 createConfiguration(kVgaWidth, kVgaHeight, Format::RGBA_8888, kMaxFps);
Jan Sebechlebsky042d1fb2023-12-12 16:37:00 +0100203
204 ASSERT_TRUE(mCameraService->registerCamera(ndkToken, config, &aidlRet).isOk());
205
206 EXPECT_TRUE(aidlRet);
207 EXPECT_THAT(getCameraIds(), SizeIs(1));
208}
209
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100210TEST_F(VirtualCameraServiceTest, RegisterCameraTwiceSecondReturnsFalse) {
211 createCamera();
212 bool aidlRet;
213
214 ASSERT_TRUE(mCameraService
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100215 ->registerCamera(mNdkOwnerToken, mVgaYUV420OnlyConfiguration,
216 &aidlRet)
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100217 .isOk());
218 EXPECT_FALSE(aidlRet);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100219 EXPECT_THAT(getCameraIds(), SizeIs(1));
220}
221
222TEST_F(VirtualCameraServiceTest, EmptyConfigurationFails) {
223 bool aidlRet;
224
225 ASSERT_FALSE(mCameraService
226 ->registerCamera(mNdkOwnerToken,
227 kEmptyVirtualCameraConfiguration, &aidlRet)
228 .isOk());
229 EXPECT_FALSE(aidlRet);
230 EXPECT_THAT(getCameraIds(), IsEmpty());
231}
232
233TEST_F(VirtualCameraServiceTest, ConfigurationWithUnsupportedPixelFormatFails) {
234 bool aidlRet;
235
236 VirtualCameraConfiguration config =
Biswarup Pal112458f2023-12-28 19:50:17 +0000237 createConfiguration(kVgaWidth, kVgaHeight, Format::UNKNOWN, kMaxFps);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100238
239 ASSERT_FALSE(
240 mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
241 EXPECT_FALSE(aidlRet);
242 EXPECT_THAT(getCameraIds(), IsEmpty());
243}
244
245TEST_F(VirtualCameraServiceTest, ConfigurationWithTooHighResFails) {
246 bool aidlRet;
247 VirtualCameraConfiguration config =
Biswarup Pal112458f2023-12-28 19:50:17 +0000248 createConfiguration(1000000, 1000000, Format::YUV_420_888, kMaxFps);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100249
250 ASSERT_FALSE(
251 mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
252 EXPECT_FALSE(aidlRet);
253 EXPECT_THAT(getCameraIds(), IsEmpty());
254}
255
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100256TEST_F(VirtualCameraServiceTest, ConfigurationWithNegativeResolutionFails) {
257 bool aidlRet;
258 VirtualCameraConfiguration config =
Biswarup Pal112458f2023-12-28 19:50:17 +0000259 createConfiguration(-1, kVgaHeight, Format::YUV_420_888, kMaxFps);
Biswarup Pal6152a302023-12-19 12:44:09 +0000260
261 ASSERT_FALSE(
262 mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
263 EXPECT_FALSE(aidlRet);
264 EXPECT_THAT(getCameraIds(), IsEmpty());
265}
266
267TEST_F(VirtualCameraServiceTest, ConfigurationWithTooLowMaxFpsFails) {
268 bool aidlRet;
269 VirtualCameraConfiguration config =
Biswarup Pal112458f2023-12-28 19:50:17 +0000270 createConfiguration(kVgaWidth, kVgaHeight, Format::YUV_420_888, 0);
Biswarup Pal6152a302023-12-19 12:44:09 +0000271
272 ASSERT_FALSE(
273 mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
274 EXPECT_FALSE(aidlRet);
275 EXPECT_THAT(getCameraIds(), IsEmpty());
276}
277
278TEST_F(VirtualCameraServiceTest, ConfigurationWithTooHighMaxFpsFails) {
279 bool aidlRet;
280 VirtualCameraConfiguration config =
Biswarup Pal112458f2023-12-28 19:50:17 +0000281 createConfiguration(kVgaWidth, kVgaHeight, Format::YUV_420_888, 90);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100282
283 ASSERT_FALSE(
284 mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
285 EXPECT_FALSE(aidlRet);
286 EXPECT_THAT(getCameraIds(), IsEmpty());
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100287}
288
289TEST_F(VirtualCameraServiceTest, GetCamera) {
290 createCamera();
291
292 EXPECT_THAT(mCameraService->getCamera(mNdkOwnerToken), Not(IsNull()));
293
294 sp<BBinder> otherToken = sp<BBinder>::make();
295 EXPECT_THAT(mCameraService->getCamera(
296 ndk::SpAIBinder(AIBinder_fromPlatformBinder(otherToken))),
297 IsNull());
298}
299
300TEST_F(VirtualCameraServiceTest, UnregisterCamera) {
301 createCamera();
302
303 EXPECT_THAT(mCameraService->getCamera(mNdkOwnerToken), Not(IsNull()));
304
305 mCameraService->unregisterCamera(mNdkOwnerToken);
306
307 EXPECT_THAT(mCameraService->getCamera(mNdkOwnerToken), IsNull());
308}
309
Jan Sebechlebskyde6f16f2023-11-29 09:27:36 +0100310TEST_F(VirtualCameraServiceTest, RegisterCameraWithoutPermissionFails) {
311 bool aidlRet;
312 EXPECT_CALL(mMockPermissionsProxy,
313 checkCallingPermission(kCreateVirtualDevicePermissions))
314 .WillOnce(Return(false));
315
316 EXPECT_THAT(mCameraService
317 ->registerCamera(mNdkOwnerToken, mVgaYUV420OnlyConfiguration,
318 &aidlRet)
319 .getExceptionCode(),
320 Eq(EX_SECURITY));
321}
322
323TEST_F(VirtualCameraServiceTest, UnregisterCameraWithoutPermissionFails) {
324 EXPECT_CALL(mMockPermissionsProxy,
325 checkCallingPermission(kCreateVirtualDevicePermissions))
326 .WillOnce(Return(false));
327
328 EXPECT_THAT(
329 mCameraService->unregisterCamera(mNdkOwnerToken).getExceptionCode(),
330 Eq(EX_SECURITY));
331}
332
333TEST_F(VirtualCameraServiceTest, GetIdWithoutPermissionFails) {
334 int32_t aidlRet;
335 EXPECT_CALL(mMockPermissionsProxy,
336 checkCallingPermission(kCreateVirtualDevicePermissions))
337 .WillOnce(Return(false));
338
339 EXPECT_THAT(
340 mCameraService->getCameraId(mNdkOwnerToken, &aidlRet).getExceptionCode(),
341 Eq(EX_SECURITY));
342}
343
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100344TEST_F(VirtualCameraServiceTest, UnregisterCameraWithUnknownToken) {
345 createCamera();
346
347 EXPECT_THAT(mCameraService->getCamera(mNdkOwnerToken), Not(IsNull()));
348
349 auto otherToken = sp<BBinder>::make();
350 ndk::SpAIBinder ndkOtherToken(AIBinder_fromPlatformBinder(otherToken));
351 mCameraService->unregisterCamera(ndkOtherToken);
352
353 EXPECT_THAT(mCameraService->getCamera(mNdkOwnerToken), Not(IsNull()));
354}
355
356TEST_F(VirtualCameraServiceTest, ShellCmdWithNullArgs) {
357 EXPECT_EQ(mCameraService->handleShellCommand(
358 /*in=*/mDevNullFd, /*out=*/mDevNullFd, /*err=*/mDevNullFd,
359 /*args=*/nullptr, /*numArgs=*/1),
360 STATUS_BAD_VALUE);
361
362 std::array<const char*, 1> args{nullptr};
363 EXPECT_EQ(mCameraService->handleShellCommand(
364 /*in=*/mDevNullFd, /*out=*/mDevNullFd, /*err=*/mDevNullFd,
365 args.data(), /*numArgs=*/1),
366 STATUS_BAD_VALUE);
367}
368
Jan Sebechlebsky76d7e212023-11-28 14:10:25 +0100369TEST_F(VirtualCameraServiceTest, ShellCmdWithNoArgs) {
370 EXPECT_EQ(mCameraService->handleShellCommand(
371 /*in=*/mDevNullFd, /*out=*/mDevNullFd, /*err=*/mDevNullFd,
372 /*args=*/nullptr, /*numArgs=*/0),
373 STATUS_OK);
374}
375
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100376TEST_F(VirtualCameraServiceTest, TestCameraShellCmd) {
377 execute_shell_command("enable_test_camera");
378
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100379 std::vector<std::string> cameraIdsAfterEnable = getCameraIds();
380 EXPECT_THAT(cameraIdsAfterEnable, SizeIs(1));
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100381
382 execute_shell_command("disable_test_camera");
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100383
384 std::vector<std::string> cameraIdsAfterDisable = getCameraIds();
385 EXPECT_THAT(cameraIdsAfterDisable, IsEmpty());
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100386}
387
Marvin Ramina8196132024-03-15 15:55:22 +0000388TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithId) {
Jan Sebechlebsky685ba1e2024-03-25 10:33:09 +0100389 execute_shell_command("enable_test_camera 12345");
Marvin Ramina8196132024-03-15 15:55:22 +0000390
391 std::vector<std::string> cameraIdsAfterEnable = getCameraIds();
Jan Sebechlebsky685ba1e2024-03-25 10:33:09 +0100392 EXPECT_THAT(cameraIdsAfterEnable, ElementsAre("device@1.1/virtual/12345"));
Marvin Ramina8196132024-03-15 15:55:22 +0000393
394 execute_shell_command("disable_test_camera");
395
396 std::vector<std::string> cameraIdsAfterDisable = getCameraIds();
397 EXPECT_THAT(cameraIdsAfterDisable, IsEmpty());
398}
399
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100400} // namespace
401} // namespace virtualcamera
402} // namespace companion
403} // namespace android