blob: f4d504205fa9c5c17c8e3bdc7ce6958656f965f2 [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"
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;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010042using ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration;
43using ::aidl::android::hardware::camera::common::CameraDeviceStatus;
44using ::aidl::android::hardware::camera::common::TorchModeStatus;
45using ::aidl::android::hardware::camera::provider::BnCameraProviderCallback;
46using ::aidl::android::hardware::graphics::common::PixelFormat;
47using ::aidl::android::view::Surface;
48using ::testing::_;
49using ::testing::Eq;
50using ::testing::Ge;
51using ::testing::IsEmpty;
52using ::testing::IsNull;
53using ::testing::Not;
Jan Sebechlebskyde6f16f2023-11-29 09:27:36 +010054using ::testing::Return;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010055using ::testing::SizeIs;
56
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010057constexpr int kVgaWidth = 640;
58constexpr int kVgaHeight = 480;
Jan Sebechlebskyde6f16f2023-11-29 09:27:36 +010059constexpr char kCreateVirtualDevicePermissions[] =
60 "android.permission.CREATE_VIRTUAL_DEVICE";
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010061
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010062const VirtualCameraConfiguration kEmptyVirtualCameraConfiguration;
63
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010064VirtualCameraConfiguration createConfiguration(const int width, const int height,
65 const Format format) {
66 VirtualCameraConfiguration configuration;
67 configuration.supportedStreamConfigs.push_back(
68 {.width = width, .height = height, .pixelFormat = format});
69 return configuration;
70}
71
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010072class MockCameraProviderCallback : public BnCameraProviderCallback {
73 public:
74 MOCK_METHOD(ndk::ScopedAStatus, cameraDeviceStatusChange,
75 (const std::string&, CameraDeviceStatus), (override));
76 MOCK_METHOD(ndk::ScopedAStatus, torchModeStatusChange,
77 (const std::string&, TorchModeStatus), (override));
78 MOCK_METHOD(ndk::ScopedAStatus, physicalCameraDeviceStatusChange,
79 (const std::string&, const std::string&, CameraDeviceStatus),
80 (override));
81};
82
Jan Sebechlebskyde6f16f2023-11-29 09:27:36 +010083class MockPermissionsProxy : public PermissionsProxy {
84 public:
85 MOCK_METHOD(bool, checkCallingPermission, (const std::string&),
86 (const override));
87};
88
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010089class VirtualCameraServiceTest : public ::testing::Test {
90 public:
91 void SetUp() override {
92 mCameraProvider = ndk::SharedRefBase::make<VirtualCameraProvider>();
93 mMockCameraProviderCallback =
94 ndk::SharedRefBase::make<MockCameraProviderCallback>();
95 ON_CALL(*mMockCameraProviderCallback, cameraDeviceStatusChange)
96 .WillByDefault([](const std::string&, CameraDeviceStatus) {
97 return ndk::ScopedAStatus::ok();
98 });
99 mCameraProvider->setCallback(mMockCameraProviderCallback);
Jan Sebechlebskyde6f16f2023-11-29 09:27:36 +0100100 mCameraService = ndk::SharedRefBase::make<VirtualCameraService>(
101 mCameraProvider, mMockPermissionsProxy);
102
103 ON_CALL(mMockPermissionsProxy, checkCallingPermission)
104 .WillByDefault(Return(true));
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100105
106 mDevNullFd = open("/dev/null", O_RDWR);
107 ASSERT_THAT(mDevNullFd, Ge(0));
108 }
109
110 void createCamera() {
111 mOwnerToken = sp<BBinder>::make();
112 mNdkOwnerToken.set(AIBinder_fromPlatformBinder(mOwnerToken));
113 bool aidlRet;
114
115 ASSERT_TRUE(mCameraService
116 ->registerCamera(mNdkOwnerToken,
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100117 mVgaYUV420OnlyConfiguration, &aidlRet)
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100118 .isOk());
119 ASSERT_TRUE(aidlRet);
120 }
121
122 void TearDown() override {
123 close(mDevNullFd);
124 }
125
126 void execute_shell_command(const std::string cmd) {
127 std::array<const char*, 1> args{cmd.data()};
128 ASSERT_THAT(
129 mCameraService->handleShellCommand(mDevNullFd, mDevNullFd, mDevNullFd,
130 args.data(), args.size()),
131 Eq(NO_ERROR));
132 }
133
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100134 std::vector<std::string> getCameraIds() {
135 std::vector<std::string> cameraIds;
136 EXPECT_TRUE(mCameraProvider->getCameraIdList(&cameraIds).isOk());
137 return cameraIds;
138 }
139
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100140 protected:
141 std::shared_ptr<VirtualCameraService> mCameraService;
142 std::shared_ptr<VirtualCameraProvider> mCameraProvider;
143 std::shared_ptr<MockCameraProviderCallback> mMockCameraProviderCallback =
144 ndk::SharedRefBase::make<MockCameraProviderCallback>();
Jan Sebechlebskyde6f16f2023-11-29 09:27:36 +0100145 MockPermissionsProxy mMockPermissionsProxy;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100146
147 sp<BBinder> mOwnerToken;
148 ndk::SpAIBinder mNdkOwnerToken;
149
150 int mDevNullFd;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100151
152 VirtualCameraConfiguration mVgaYUV420OnlyConfiguration =
153 createConfiguration(kVgaWidth, kVgaHeight, Format::YUV_420_888);
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100154};
155
156TEST_F(VirtualCameraServiceTest, RegisterCameraSucceeds) {
157 sp<BBinder> token = sp<BBinder>::make();
158 ndk::SpAIBinder ndkToken(AIBinder_fromPlatformBinder(token));
159 bool aidlRet;
160
161 ASSERT_TRUE(
162 mCameraService
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100163 ->registerCamera(ndkToken, mVgaYUV420OnlyConfiguration, &aidlRet)
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100164 .isOk());
165
166 EXPECT_TRUE(aidlRet);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100167 EXPECT_THAT(getCameraIds(), SizeIs(1));
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100168}
169
170TEST_F(VirtualCameraServiceTest, RegisterCameraTwiceSecondReturnsFalse) {
171 createCamera();
172 bool aidlRet;
173
174 ASSERT_TRUE(mCameraService
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100175 ->registerCamera(mNdkOwnerToken, mVgaYUV420OnlyConfiguration,
176 &aidlRet)
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100177 .isOk());
178 EXPECT_FALSE(aidlRet);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100179 EXPECT_THAT(getCameraIds(), SizeIs(1));
180}
181
182TEST_F(VirtualCameraServiceTest, EmptyConfigurationFails) {
183 bool aidlRet;
184
185 ASSERT_FALSE(mCameraService
186 ->registerCamera(mNdkOwnerToken,
187 kEmptyVirtualCameraConfiguration, &aidlRet)
188 .isOk());
189 EXPECT_FALSE(aidlRet);
190 EXPECT_THAT(getCameraIds(), IsEmpty());
191}
192
193TEST_F(VirtualCameraServiceTest, ConfigurationWithUnsupportedPixelFormatFails) {
194 bool aidlRet;
195
196 VirtualCameraConfiguration config =
197 createConfiguration(kVgaWidth, kVgaHeight, Format::UNKNOWN);
198
199 ASSERT_FALSE(
200 mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
201 EXPECT_FALSE(aidlRet);
202 EXPECT_THAT(getCameraIds(), IsEmpty());
203}
204
205TEST_F(VirtualCameraServiceTest, ConfigurationWithTooHighResFails) {
206 bool aidlRet;
207 VirtualCameraConfiguration config =
208 createConfiguration(1000000, 1000000, Format::YUV_420_888);
209
210 ASSERT_FALSE(
211 mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
212 EXPECT_FALSE(aidlRet);
213 EXPECT_THAT(getCameraIds(), IsEmpty());
214}
215
216TEST_F(VirtualCameraServiceTest, ConfigurationWithUnalignedResolutionFails) {
217 bool aidlRet;
218 VirtualCameraConfiguration config =
219 createConfiguration(641, 481, Format::YUV_420_888);
220
221 ASSERT_FALSE(
222 mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
223 EXPECT_FALSE(aidlRet);
224 EXPECT_THAT(getCameraIds(), IsEmpty());
225}
226
227TEST_F(VirtualCameraServiceTest, ConfigurationWithNegativeResolutionFails) {
228 bool aidlRet;
229 VirtualCameraConfiguration config =
230 createConfiguration(-1, kVgaHeight, Format::YUV_420_888);
231
232 ASSERT_FALSE(
233 mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
234 EXPECT_FALSE(aidlRet);
235 EXPECT_THAT(getCameraIds(), IsEmpty());
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100236}
237
238TEST_F(VirtualCameraServiceTest, GetCamera) {
239 createCamera();
240
241 EXPECT_THAT(mCameraService->getCamera(mNdkOwnerToken), Not(IsNull()));
242
243 sp<BBinder> otherToken = sp<BBinder>::make();
244 EXPECT_THAT(mCameraService->getCamera(
245 ndk::SpAIBinder(AIBinder_fromPlatformBinder(otherToken))),
246 IsNull());
247}
248
249TEST_F(VirtualCameraServiceTest, UnregisterCamera) {
250 createCamera();
251
252 EXPECT_THAT(mCameraService->getCamera(mNdkOwnerToken), Not(IsNull()));
253
254 mCameraService->unregisterCamera(mNdkOwnerToken);
255
256 EXPECT_THAT(mCameraService->getCamera(mNdkOwnerToken), IsNull());
257}
258
Jan Sebechlebskyde6f16f2023-11-29 09:27:36 +0100259TEST_F(VirtualCameraServiceTest, RegisterCameraWithoutPermissionFails) {
260 bool aidlRet;
261 EXPECT_CALL(mMockPermissionsProxy,
262 checkCallingPermission(kCreateVirtualDevicePermissions))
263 .WillOnce(Return(false));
264
265 EXPECT_THAT(mCameraService
266 ->registerCamera(mNdkOwnerToken, mVgaYUV420OnlyConfiguration,
267 &aidlRet)
268 .getExceptionCode(),
269 Eq(EX_SECURITY));
270}
271
272TEST_F(VirtualCameraServiceTest, UnregisterCameraWithoutPermissionFails) {
273 EXPECT_CALL(mMockPermissionsProxy,
274 checkCallingPermission(kCreateVirtualDevicePermissions))
275 .WillOnce(Return(false));
276
277 EXPECT_THAT(
278 mCameraService->unregisterCamera(mNdkOwnerToken).getExceptionCode(),
279 Eq(EX_SECURITY));
280}
281
282TEST_F(VirtualCameraServiceTest, GetIdWithoutPermissionFails) {
283 int32_t aidlRet;
284 EXPECT_CALL(mMockPermissionsProxy,
285 checkCallingPermission(kCreateVirtualDevicePermissions))
286 .WillOnce(Return(false));
287
288 EXPECT_THAT(
289 mCameraService->getCameraId(mNdkOwnerToken, &aidlRet).getExceptionCode(),
290 Eq(EX_SECURITY));
291}
292
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100293TEST_F(VirtualCameraServiceTest, UnregisterCameraWithUnknownToken) {
294 createCamera();
295
296 EXPECT_THAT(mCameraService->getCamera(mNdkOwnerToken), Not(IsNull()));
297
298 auto otherToken = sp<BBinder>::make();
299 ndk::SpAIBinder ndkOtherToken(AIBinder_fromPlatformBinder(otherToken));
300 mCameraService->unregisterCamera(ndkOtherToken);
301
302 EXPECT_THAT(mCameraService->getCamera(mNdkOwnerToken), Not(IsNull()));
303}
304
305TEST_F(VirtualCameraServiceTest, ShellCmdWithNullArgs) {
306 EXPECT_EQ(mCameraService->handleShellCommand(
307 /*in=*/mDevNullFd, /*out=*/mDevNullFd, /*err=*/mDevNullFd,
308 /*args=*/nullptr, /*numArgs=*/1),
309 STATUS_BAD_VALUE);
310
311 std::array<const char*, 1> args{nullptr};
312 EXPECT_EQ(mCameraService->handleShellCommand(
313 /*in=*/mDevNullFd, /*out=*/mDevNullFd, /*err=*/mDevNullFd,
314 args.data(), /*numArgs=*/1),
315 STATUS_BAD_VALUE);
316}
317
Jan Sebechlebsky76d7e212023-11-28 14:10:25 +0100318TEST_F(VirtualCameraServiceTest, ShellCmdWithNoArgs) {
319 EXPECT_EQ(mCameraService->handleShellCommand(
320 /*in=*/mDevNullFd, /*out=*/mDevNullFd, /*err=*/mDevNullFd,
321 /*args=*/nullptr, /*numArgs=*/0),
322 STATUS_OK);
323}
324
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100325TEST_F(VirtualCameraServiceTest, TestCameraShellCmd) {
326 execute_shell_command("enable_test_camera");
327
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100328 std::vector<std::string> cameraIdsAfterEnable = getCameraIds();
329 EXPECT_THAT(cameraIdsAfterEnable, SizeIs(1));
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100330
331 execute_shell_command("disable_test_camera");
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100332
333 std::vector<std::string> cameraIdsAfterDisable = getCameraIds();
334 EXPECT_THAT(cameraIdsAfterDisable, IsEmpty());
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100335}
336
337} // namespace
338} // namespace virtualcamera
339} // namespace companion
340} // namespace android