blob: f931cb4b31563f99af4e8131c082c1e0f2f5ba39 [file] [log] [blame]
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +01001/*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
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"
32#include "utils/Errors.h"
33
34namespace android {
35namespace companion {
36namespace virtualcamera {
37namespace {
38
39using ::aidl::android::companion::virtualcamera::BnVirtualCameraCallback;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010040using ::aidl::android::companion::virtualcamera::Format;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010041using ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration;
42using ::aidl::android::hardware::camera::common::CameraDeviceStatus;
43using ::aidl::android::hardware::camera::common::TorchModeStatus;
44using ::aidl::android::hardware::camera::provider::BnCameraProviderCallback;
45using ::aidl::android::hardware::graphics::common::PixelFormat;
46using ::aidl::android::view::Surface;
47using ::testing::_;
48using ::testing::Eq;
49using ::testing::Ge;
50using ::testing::IsEmpty;
51using ::testing::IsNull;
52using ::testing::Not;
53using ::testing::SizeIs;
54
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010055constexpr int kVgaWidth = 640;
56constexpr int kVgaHeight = 480;
57
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010058const VirtualCameraConfiguration kEmptyVirtualCameraConfiguration;
59
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010060VirtualCameraConfiguration createConfiguration(const int width, const int height,
61 const Format format) {
62 VirtualCameraConfiguration configuration;
63 configuration.supportedStreamConfigs.push_back(
64 {.width = width, .height = height, .pixelFormat = format});
65 return configuration;
66}
67
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010068class MockCameraProviderCallback : public BnCameraProviderCallback {
69 public:
70 MOCK_METHOD(ndk::ScopedAStatus, cameraDeviceStatusChange,
71 (const std::string&, CameraDeviceStatus), (override));
72 MOCK_METHOD(ndk::ScopedAStatus, torchModeStatusChange,
73 (const std::string&, TorchModeStatus), (override));
74 MOCK_METHOD(ndk::ScopedAStatus, physicalCameraDeviceStatusChange,
75 (const std::string&, const std::string&, CameraDeviceStatus),
76 (override));
77};
78
79class VirtualCameraServiceTest : public ::testing::Test {
80 public:
81 void SetUp() override {
82 mCameraProvider = ndk::SharedRefBase::make<VirtualCameraProvider>();
83 mMockCameraProviderCallback =
84 ndk::SharedRefBase::make<MockCameraProviderCallback>();
85 ON_CALL(*mMockCameraProviderCallback, cameraDeviceStatusChange)
86 .WillByDefault([](const std::string&, CameraDeviceStatus) {
87 return ndk::ScopedAStatus::ok();
88 });
89 mCameraProvider->setCallback(mMockCameraProviderCallback);
90 mCameraService =
91 ndk::SharedRefBase::make<VirtualCameraService>(mCameraProvider);
92
93 mDevNullFd = open("/dev/null", O_RDWR);
94 ASSERT_THAT(mDevNullFd, Ge(0));
95 }
96
97 void createCamera() {
98 mOwnerToken = sp<BBinder>::make();
99 mNdkOwnerToken.set(AIBinder_fromPlatformBinder(mOwnerToken));
100 bool aidlRet;
101
102 ASSERT_TRUE(mCameraService
103 ->registerCamera(mNdkOwnerToken,
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100104 mVgaYUV420OnlyConfiguration, &aidlRet)
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100105 .isOk());
106 ASSERT_TRUE(aidlRet);
107 }
108
109 void TearDown() override {
110 close(mDevNullFd);
111 }
112
113 void execute_shell_command(const std::string cmd) {
114 std::array<const char*, 1> args{cmd.data()};
115 ASSERT_THAT(
116 mCameraService->handleShellCommand(mDevNullFd, mDevNullFd, mDevNullFd,
117 args.data(), args.size()),
118 Eq(NO_ERROR));
119 }
120
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100121 std::vector<std::string> getCameraIds() {
122 std::vector<std::string> cameraIds;
123 EXPECT_TRUE(mCameraProvider->getCameraIdList(&cameraIds).isOk());
124 return cameraIds;
125 }
126
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100127 protected:
128 std::shared_ptr<VirtualCameraService> mCameraService;
129 std::shared_ptr<VirtualCameraProvider> mCameraProvider;
130 std::shared_ptr<MockCameraProviderCallback> mMockCameraProviderCallback =
131 ndk::SharedRefBase::make<MockCameraProviderCallback>();
132
133 sp<BBinder> mOwnerToken;
134 ndk::SpAIBinder mNdkOwnerToken;
135
136 int mDevNullFd;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100137
138 VirtualCameraConfiguration mVgaYUV420OnlyConfiguration =
139 createConfiguration(kVgaWidth, kVgaHeight, Format::YUV_420_888);
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100140};
141
142TEST_F(VirtualCameraServiceTest, RegisterCameraSucceeds) {
143 sp<BBinder> token = sp<BBinder>::make();
144 ndk::SpAIBinder ndkToken(AIBinder_fromPlatformBinder(token));
145 bool aidlRet;
146
147 ASSERT_TRUE(
148 mCameraService
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100149 ->registerCamera(ndkToken, mVgaYUV420OnlyConfiguration, &aidlRet)
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100150 .isOk());
151
152 EXPECT_TRUE(aidlRet);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100153 EXPECT_THAT(getCameraIds(), SizeIs(1));
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100154}
155
156TEST_F(VirtualCameraServiceTest, RegisterCameraTwiceSecondReturnsFalse) {
157 createCamera();
158 bool aidlRet;
159
160 ASSERT_TRUE(mCameraService
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100161 ->registerCamera(mNdkOwnerToken, mVgaYUV420OnlyConfiguration,
162 &aidlRet)
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100163 .isOk());
164 EXPECT_FALSE(aidlRet);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100165 EXPECT_THAT(getCameraIds(), SizeIs(1));
166}
167
168TEST_F(VirtualCameraServiceTest, EmptyConfigurationFails) {
169 bool aidlRet;
170
171 ASSERT_FALSE(mCameraService
172 ->registerCamera(mNdkOwnerToken,
173 kEmptyVirtualCameraConfiguration, &aidlRet)
174 .isOk());
175 EXPECT_FALSE(aidlRet);
176 EXPECT_THAT(getCameraIds(), IsEmpty());
177}
178
179TEST_F(VirtualCameraServiceTest, ConfigurationWithUnsupportedPixelFormatFails) {
180 bool aidlRet;
181
182 VirtualCameraConfiguration config =
183 createConfiguration(kVgaWidth, kVgaHeight, Format::UNKNOWN);
184
185 ASSERT_FALSE(
186 mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
187 EXPECT_FALSE(aidlRet);
188 EXPECT_THAT(getCameraIds(), IsEmpty());
189}
190
191TEST_F(VirtualCameraServiceTest, ConfigurationWithTooHighResFails) {
192 bool aidlRet;
193 VirtualCameraConfiguration config =
194 createConfiguration(1000000, 1000000, Format::YUV_420_888);
195
196 ASSERT_FALSE(
197 mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
198 EXPECT_FALSE(aidlRet);
199 EXPECT_THAT(getCameraIds(), IsEmpty());
200}
201
202TEST_F(VirtualCameraServiceTest, ConfigurationWithUnalignedResolutionFails) {
203 bool aidlRet;
204 VirtualCameraConfiguration config =
205 createConfiguration(641, 481, Format::YUV_420_888);
206
207 ASSERT_FALSE(
208 mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
209 EXPECT_FALSE(aidlRet);
210 EXPECT_THAT(getCameraIds(), IsEmpty());
211}
212
213TEST_F(VirtualCameraServiceTest, ConfigurationWithNegativeResolutionFails) {
214 bool aidlRet;
215 VirtualCameraConfiguration config =
216 createConfiguration(-1, kVgaHeight, Format::YUV_420_888);
217
218 ASSERT_FALSE(
219 mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
220 EXPECT_FALSE(aidlRet);
221 EXPECT_THAT(getCameraIds(), IsEmpty());
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100222}
223
224TEST_F(VirtualCameraServiceTest, GetCamera) {
225 createCamera();
226
227 EXPECT_THAT(mCameraService->getCamera(mNdkOwnerToken), Not(IsNull()));
228
229 sp<BBinder> otherToken = sp<BBinder>::make();
230 EXPECT_THAT(mCameraService->getCamera(
231 ndk::SpAIBinder(AIBinder_fromPlatformBinder(otherToken))),
232 IsNull());
233}
234
235TEST_F(VirtualCameraServiceTest, UnregisterCamera) {
236 createCamera();
237
238 EXPECT_THAT(mCameraService->getCamera(mNdkOwnerToken), Not(IsNull()));
239
240 mCameraService->unregisterCamera(mNdkOwnerToken);
241
242 EXPECT_THAT(mCameraService->getCamera(mNdkOwnerToken), IsNull());
243}
244
245TEST_F(VirtualCameraServiceTest, UnregisterCameraWithUnknownToken) {
246 createCamera();
247
248 EXPECT_THAT(mCameraService->getCamera(mNdkOwnerToken), Not(IsNull()));
249
250 auto otherToken = sp<BBinder>::make();
251 ndk::SpAIBinder ndkOtherToken(AIBinder_fromPlatformBinder(otherToken));
252 mCameraService->unregisterCamera(ndkOtherToken);
253
254 EXPECT_THAT(mCameraService->getCamera(mNdkOwnerToken), Not(IsNull()));
255}
256
257TEST_F(VirtualCameraServiceTest, ShellCmdWithNullArgs) {
258 EXPECT_EQ(mCameraService->handleShellCommand(
259 /*in=*/mDevNullFd, /*out=*/mDevNullFd, /*err=*/mDevNullFd,
260 /*args=*/nullptr, /*numArgs=*/1),
261 STATUS_BAD_VALUE);
262
263 std::array<const char*, 1> args{nullptr};
264 EXPECT_EQ(mCameraService->handleShellCommand(
265 /*in=*/mDevNullFd, /*out=*/mDevNullFd, /*err=*/mDevNullFd,
266 args.data(), /*numArgs=*/1),
267 STATUS_BAD_VALUE);
268}
269
Jan Sebechlebsky76d7e212023-11-28 14:10:25 +0100270TEST_F(VirtualCameraServiceTest, ShellCmdWithNoArgs) {
271 EXPECT_EQ(mCameraService->handleShellCommand(
272 /*in=*/mDevNullFd, /*out=*/mDevNullFd, /*err=*/mDevNullFd,
273 /*args=*/nullptr, /*numArgs=*/0),
274 STATUS_OK);
275}
276
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100277TEST_F(VirtualCameraServiceTest, TestCameraShellCmd) {
278 execute_shell_command("enable_test_camera");
279
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100280 std::vector<std::string> cameraIdsAfterEnable = getCameraIds();
281 EXPECT_THAT(cameraIdsAfterEnable, SizeIs(1));
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100282
283 execute_shell_command("disable_test_camera");
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100284
285 std::vector<std::string> cameraIdsAfterDisable = getCameraIds();
286 EXPECT_THAT(cameraIdsAfterDisable, IsEmpty());
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100287}
288
289} // namespace
290} // namespace virtualcamera
291} // namespace companion
292} // namespace android