1 /*
2 * Copyright (C) 2019 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 #define LOG_TAG "CameraDeviceSessionTests"
18 #include <dlfcn.h>
19 #include <gtest/gtest.h>
20 #include <log/log.h>
21 #include <sys/stat.h>
22
23 #include <algorithm>
24
25 #include "gralloc_buffer_allocator.h"
26 #include "mock_device_session_hwl.h"
27 #include "test_utils.h"
28 #include "utils.h"
29
30 namespace android {
31 namespace google_camera_hal {
32 namespace {
33
34 using ::testing::_;
35 using ::testing::AtLeast;
36 using ::testing::Return;
37
38 // HAL external capture session library path
39 #if defined(_LP64)
40 constexpr char kExternalCaptureSessionDir[] =
41 "/vendor/lib64/camera/capture_sessions/";
42 #else // defined(_LP64)
43 constexpr char kExternalCaptureSessionDir[] =
44 "/vendor/lib/camera/capture_sessions/";
45 #endif
46
47 class CameraDeviceSessionTests : public ::testing::Test {
48 protected:
49 static constexpr uint32_t kCaptureTimeoutMs = 3000;
50 std::vector<GetCaptureSessionFactoryFunc> external_session_factory_entries_;
51 std::vector<void*> external_capture_session_lib_handles_;
52
CameraDeviceSessionTests()53 CameraDeviceSessionTests() {
54 LoadExternalCaptureSession();
55 }
56
~CameraDeviceSessionTests()57 ~CameraDeviceSessionTests() {
58 for (auto lib_handle : external_capture_session_lib_handles_) {
59 dlclose(lib_handle);
60 }
61 }
62
LoadExternalCaptureSession()63 status_t LoadExternalCaptureSession() {
64 if (external_session_factory_entries_.size() > 0) {
65 ALOGI("%s: External capture session libraries already loaded; skip.",
66 __FUNCTION__);
67 return OK;
68 }
69
70 for (const auto& lib_path :
71 utils::FindLibraryPaths(kExternalCaptureSessionDir)) {
72 ALOGI("%s: Loading %s", __FUNCTION__, lib_path.c_str());
73 void* lib_handle = nullptr;
74 lib_handle = dlopen(lib_path.c_str(), RTLD_NOW);
75 if (lib_handle == nullptr) {
76 ALOGW("Failed loading %s.", lib_path.c_str());
77 continue;
78 }
79
80 GetCaptureSessionFactoryFunc external_session_factory_t =
81 reinterpret_cast<GetCaptureSessionFactoryFunc>(
82 dlsym(lib_handle, "GetCaptureSessionFactory"));
83 if (external_session_factory_t == nullptr) {
84 ALOGE("%s: dlsym failed (%s) when loading %s.", __FUNCTION__,
85 "GetCaptureSessionFactory", lib_path.c_str());
86 dlclose(lib_handle);
87 lib_handle = nullptr;
88 continue;
89 }
90
91 external_session_factory_entries_.push_back(external_session_factory_t);
92 }
93
94 return OK;
95 }
96
CreateMockSessionHwlAndCheck(std::unique_ptr<MockDeviceSessionHwl> * session_hwl)97 void CreateMockSessionHwlAndCheck(
98 std::unique_ptr<MockDeviceSessionHwl>* session_hwl) {
99 ASSERT_NE(session_hwl, nullptr);
100
101 *session_hwl = std::make_unique<MockDeviceSessionHwl>();
102 ASSERT_NE(*session_hwl, nullptr);
103 }
104
CreateSessionAndCheck(std::unique_ptr<MockDeviceSessionHwl> session_hwl,std::unique_ptr<CameraDeviceSession> * session)105 void CreateSessionAndCheck(std::unique_ptr<MockDeviceSessionHwl> session_hwl,
106 std::unique_ptr<CameraDeviceSession>* session) {
107 ASSERT_NE(session, nullptr);
108
109 *session = CameraDeviceSession::Create(std::move(session_hwl),
110 external_session_factory_entries_);
111 ASSERT_NE(*session, nullptr);
112 }
113
TestInvalidDefaultRequestSettingsForType(RequestTemplate type)114 void TestInvalidDefaultRequestSettingsForType(RequestTemplate type) {
115 std::unique_ptr<MockDeviceSessionHwl> session_hwl;
116 CreateMockSessionHwlAndCheck(&session_hwl);
117 session_hwl->DelegateCallsToFakeSession();
118
119 EXPECT_CALL(*session_hwl, ConstructDefaultRequestSettings(
120 /*type=*/_, /*default_settings=*/nullptr))
121 .WillRepeatedly(Return(BAD_VALUE));
122
123 std::unique_ptr<CameraDeviceSession> session;
124 CreateSessionAndCheck(std::move(session_hwl), &session);
125
126 status_t res =
127 session->ConstructDefaultRequestSettings(type,
128 /*default_settings=*/nullptr);
129 EXPECT_EQ(res, BAD_VALUE);
130 }
131
TestDefaultRequestSettingsForType(RequestTemplate type)132 void TestDefaultRequestSettingsForType(RequestTemplate type) {
133 std::unique_ptr<MockDeviceSessionHwl> session_hwl;
134 CreateMockSessionHwlAndCheck(&session_hwl);
135 session_hwl->DelegateCallsToFakeSession();
136
137 EXPECT_CALL(*session_hwl, ConstructDefaultRequestSettings(
138 /*type=*/_, /*default_settings=*/_))
139 .Times(AtLeast(1))
140 .WillRepeatedly([](RequestTemplate /*type*/,
141 std::unique_ptr<HalCameraMetadata>* default_settings) {
142 uint32_t num_entries = 128;
143 uint32_t data_bytes = 512;
144
145 *default_settings = HalCameraMetadata::Create(num_entries, data_bytes);
146 return OK;
147 });
148
149 std::unique_ptr<CameraDeviceSession> session;
150 CreateSessionAndCheck(std::move(session_hwl), &session);
151
152 std::unique_ptr<HalCameraMetadata> default_settings;
153 status_t res =
154 session->ConstructDefaultRequestSettings(type, &default_settings);
155 EXPECT_EQ(res, OK);
156 ASSERT_NE(default_settings, nullptr);
157 EXPECT_GT(default_settings->GetCameraMetadataSize(), static_cast<size_t>(0));
158 }
159
160 // Invoked when CameraDeviceSession produces a result.
ProcessCaptureResult(std::unique_ptr<CaptureResult> result)161 void ProcessCaptureResult(std::unique_ptr<CaptureResult> result) {
162 EXPECT_NE(result, nullptr);
163 if (result == nullptr) {
164 return;
165 }
166
167 std::lock_guard<std::mutex> lock(callback_lock_);
168 auto pending_result = received_results_.find(result->frame_number);
169 if (pending_result == received_results_.end()) {
170 received_results_.emplace(result->frame_number, std::move(result));
171 } else {
172 if (result->result_metadata != nullptr) {
173 // TODO(b/143902331): support partial results.
174 pending_result->second->result_metadata =
175 std::move(result->result_metadata);
176 pending_result->second->partial_result = result->partial_result;
177 }
178
179 if (!result->input_buffers.empty()) {
180 pending_result->second->input_buffers.insert(
181 pending_result->second->input_buffers.end(),
182 result->input_buffers.begin(), result->input_buffers.end());
183 }
184
185 if (!result->output_buffers.empty()) {
186 pending_result->second->output_buffers.insert(
187 pending_result->second->output_buffers.end(),
188 result->output_buffers.begin(), result->output_buffers.end());
189 }
190 }
191
192 callback_condition_.notify_one();
193 }
194
ProcessBatchCaptureResult(std::vector<std::unique_ptr<CaptureResult>> results)195 void ProcessBatchCaptureResult(
196 std::vector<std::unique_ptr<CaptureResult>> results) {
197 for (auto& result : results) {
198 ProcessCaptureResult(std::move(result));
199 }
200 }
201
202 // Invoked when CameraDeviceSession notify a message.
Notify(const NotifyMessage & message)203 void Notify(const NotifyMessage& message) {
204 std::lock_guard<std::mutex> lock(callback_lock_);
205 received_messages_.push_back(message);
206 callback_condition_.notify_one();
207 }
208
ClearResultsAndMessages()209 void ClearResultsAndMessages() {
210 std::lock_guard<std::mutex> lock(callback_lock_);
211 received_results_.clear();
212 received_messages_.clear();
213 }
214
ContainsTheSameBuffers(std::vector<StreamBuffer> buffers,std::vector<StreamBuffer> other_buffers)215 bool ContainsTheSameBuffers(std::vector<StreamBuffer> buffers,
216 std::vector<StreamBuffer> other_buffers) {
217 // Set of pairs of stream ID and buffer ID.
218 std::set<std::pair<uint32_t, uint32_t>> stream_buffer_set;
219 std::set<std::pair<uint32_t, uint32_t>> other_stream_buffer_set;
220
221 for (auto& buffer : buffers) {
222 stream_buffer_set.emplace(buffer.stream_id, buffer.buffer_id);
223 }
224
225 for (auto& buffer : other_buffers) {
226 other_stream_buffer_set.emplace(buffer.stream_id, buffer.buffer_id);
227 }
228
229 return stream_buffer_set == other_stream_buffer_set;
230 }
231
232 // Caller must lock callback_lock_
IsResultReceivedLocked(const CaptureRequest & request)233 bool IsResultReceivedLocked(const CaptureRequest& request) {
234 auto result = received_results_.find(request.frame_number);
235 if (result == received_results_.end()) {
236 return false;
237 }
238
239 if (result->second->result_metadata == nullptr) {
240 return false;
241 }
242
243 if (!ContainsTheSameBuffers(result->second->output_buffers,
244 request.output_buffers)) {
245 return false;
246 }
247
248 if (!ContainsTheSameBuffers(result->second->input_buffers,
249 request.input_buffers)) {
250 return false;
251 }
252
253 return true;
254 }
255
WaitForResult(const CaptureRequest & request,uint32_t timeout_ms)256 status_t WaitForResult(const CaptureRequest& request, uint32_t timeout_ms) {
257 std::unique_lock<std::mutex> lock(callback_lock_);
258 if (IsResultReceivedLocked(request)) {
259 return OK;
260 }
261
262 bool received = callback_condition_.wait_for(
263 lock, std::chrono::milliseconds(timeout_ms),
264 [&] { return IsResultReceivedLocked(request); });
265
266 return received ? OK : TIMED_OUT;
267 }
268
269 // Caller must lock callback_lock_
IsShutterReceivedLocked(uint32_t frame_number)270 bool IsShutterReceivedLocked(uint32_t frame_number) {
271 for (auto& message : received_messages_) {
272 if (message.type == MessageType::kShutter &&
273 message.message.shutter.frame_number == frame_number) {
274 return true;
275 }
276 }
277
278 return false;
279 }
280
WaitForShutter(uint32_t frame_number,uint32_t timeout_ms)281 status_t WaitForShutter(uint32_t frame_number, uint32_t timeout_ms) {
282 std::unique_lock<std::mutex> lock(callback_lock_);
283 if (IsShutterReceivedLocked(frame_number)) {
284 return OK;
285 }
286
287 bool received = callback_condition_.wait_for(
288 lock, std::chrono::milliseconds(timeout_ms),
289 [&] { return IsShutterReceivedLocked(frame_number); });
290
291 return received ? OK : TIMED_OUT;
292 }
293
294 std::mutex callback_lock_;
295 std::condition_variable callback_condition_; // Protected by callback_lock_.
296
297 // Maps from a frame number to the received result from CameraDeviceSession.
298 // Protected by callback_lock_.
299 std::unordered_map<uint32_t, std::unique_ptr<CaptureResult>> received_results_;
300
301 // Received messages from CameraDeviceSession. Protected by callback_lock_.
302 std::vector<NotifyMessage> received_messages_;
303 };
304
TEST_F(CameraDeviceSessionTests,Create)305 TEST_F(CameraDeviceSessionTests, Create) {
306 auto session = CameraDeviceSession::Create(
307 /*device_session_hwl=*/nullptr, external_session_factory_entries_);
308 EXPECT_EQ(session, nullptr);
309
310 uint32_t num_sessions = 5;
311 for (uint32_t i = 0; i < num_sessions; i++) {
312 std::unique_ptr<MockDeviceSessionHwl> session_hwl;
313 CreateMockSessionHwlAndCheck(&session_hwl);
314 session_hwl->DelegateCallsToFakeSession();
315 CreateSessionAndCheck(std::move(session_hwl), &session);
316 session = nullptr;
317 }
318 }
319
TEST_F(CameraDeviceSessionTests,ConstructDefaultRequestSettings)320 TEST_F(CameraDeviceSessionTests, ConstructDefaultRequestSettings) {
321 std::vector<RequestTemplate> types = {
322 RequestTemplate::kPreview, RequestTemplate::kStillCapture,
323 RequestTemplate::kVideoRecord, RequestTemplate::kVideoSnapshot,
324 RequestTemplate::kZeroShutterLag, RequestTemplate::kManual};
325
326 for (auto type : types) {
327 TestInvalidDefaultRequestSettingsForType(type);
328 TestDefaultRequestSettingsForType(type);
329 }
330 }
331
TEST_F(CameraDeviceSessionTests,ConfigurePreviewStream)332 TEST_F(CameraDeviceSessionTests, ConfigurePreviewStream) {
333 std::vector<std::pair<uint32_t, uint32_t>> preview_resolutions = {
334 std::make_pair(640, 480), std::make_pair(1280, 720),
335 std::make_pair(1920, 1080)};
336
337 std::unique_ptr<MockDeviceSessionHwl> session_hwl;
338 CreateMockSessionHwlAndCheck(&session_hwl);
339 session_hwl->DelegateCallsToFakeSession();
340
341 // Expect CreatePipeline() calls back to back.
342 EXPECT_CALL(*session_hwl, ConfigurePipeline(/*camera_id=*/_,
343 /*hwl_pipeline_callback=*/_,
344 /*request_config=*/_,
345 /*overall_config=*/_,
346 /*pipeline_id=*/_))
347 .Times(AtLeast(preview_resolutions.size()));
348
349 // Expect BuildPipelines() calls back to back.
350 EXPECT_CALL(*session_hwl, BuildPipelines())
351 .Times(AtLeast(preview_resolutions.size()));
352
353 // Expect DestroyPipelines() calls back to back except the first
354 // stream configuration.
355 EXPECT_CALL(*session_hwl, DestroyPipelines())
356 .Times(AtLeast(preview_resolutions.size() - 1));
357
358 std::unique_ptr<CameraDeviceSession> session;
359 CreateSessionAndCheck(std::move(session_hwl), &session);
360
361 std::vector<HalStream> hal_configured_streams;
362 StreamConfiguration preview_config;
363 status_t res;
364
365 for (auto& resolution : preview_resolutions) {
366 test_utils::GetPreviewOnlyStreamConfiguration(
367 &preview_config, resolution.first, resolution.second);
368 ConfigureStreamsReturn hal_config;
369 res = session->ConfigureStreams(preview_config, /*interfaceV3*/ false,
370 &hal_config);
371 hal_configured_streams = std::move(hal_config.hal_streams);
372 EXPECT_EQ(res, OK);
373 }
374 }
375
TEST_F(CameraDeviceSessionTests,PreviewRequests)376 TEST_F(CameraDeviceSessionTests, PreviewRequests) {
377 std::unique_ptr<MockDeviceSessionHwl> session_hwl;
378 CreateMockSessionHwlAndCheck(&session_hwl);
379 session_hwl->DelegateCallsToFakeSession();
380
381 // Set up mocking expections.
382 static constexpr uint32_t kNumPreviewRequests = 5;
383 EXPECT_CALL(*session_hwl, ConfigurePipeline(_, _, _, _, _)).Times(1);
384 EXPECT_CALL(*session_hwl, SubmitRequests(_, _)).Times(kNumPreviewRequests);
385
386 std::unique_ptr<CameraDeviceSession> session;
387 CreateSessionAndCheck(std::move(session_hwl), &session);
388
389 // Configure a preview stream.
390 static const uint32_t kPreviewWidth = 640;
391 static const uint32_t kPreviewHeight = 480;
392 StreamConfiguration preview_config;
393 std::vector<HalStream> hal_configured_streams;
394
395 // Set up session callback.
396 // Needs to capture the test class as the callback function references the
397 // member variables of the class
398 CameraDeviceSessionCallback session_callback = {
399 .process_capture_result =
400 [&](std::unique_ptr<CaptureResult> result) {
401 ProcessCaptureResult(std::move(result));
402 },
403 .process_batch_capture_result =
404 [&](std::vector<std::unique_ptr<CaptureResult>> results) {
405 ProcessBatchCaptureResult(std::move(results));
406 },
407 .notify = [&](const NotifyMessage& message) { Notify(message); },
408 };
409
410 ThermalCallback thermal_callback = {
411 .register_thermal_changed_callback =
412 google_camera_hal::RegisterThermalChangedCallbackFunc(
413 [](google_camera_hal::NotifyThrottlingFunc /*notify_throttling*/,
414 bool /*filter_type*/,
415 google_camera_hal::TemperatureType /*type*/) {
416 return INVALID_OPERATION;
417 }),
418 .unregister_thermal_changed_callback =
419 google_camera_hal::UnregisterThermalChangedCallbackFunc([]() {}),
420 };
421
422 session->SetSessionCallback(session_callback, thermal_callback);
423
424 test_utils::GetPreviewOnlyStreamConfiguration(&preview_config, kPreviewWidth,
425 kPreviewHeight);
426 ConfigureStreamsReturn hal_config;
427 ASSERT_EQ(session->ConfigureStreams(preview_config, /*interfaceV3*/ false,
428 &hal_config),
429 OK);
430 hal_configured_streams = std::move(hal_config.hal_streams);
431 ASSERT_EQ(hal_configured_streams.size(), static_cast<uint32_t>(1));
432
433 // Allocate buffers.
434 auto allocator = GrallocBufferAllocator::Create();
435 ASSERT_NE(allocator, nullptr);
436
437 HalBufferDescriptor buffer_descriptor = {
438 .width = preview_config.streams[0].width,
439 .height = preview_config.streams[0].height,
440 .format = hal_configured_streams[0].override_format,
441 .producer_flags = hal_configured_streams[0].producer_usage |
442 preview_config.streams[0].usage,
443 .consumer_flags = hal_configured_streams[0].consumer_usage,
444 .immediate_num_buffers =
445 std::max(hal_configured_streams[0].max_buffers, kNumPreviewRequests),
446 .max_num_buffers =
447 std::max(hal_configured_streams[0].max_buffers, kNumPreviewRequests),
448 };
449
450 std::vector<buffer_handle_t> preview_buffers;
451 ASSERT_EQ(allocator->AllocateBuffers(buffer_descriptor, &preview_buffers), OK);
452
453 std::unique_ptr<HalCameraMetadata> preview_settings;
454 ASSERT_EQ(session->ConstructDefaultRequestSettings(RequestTemplate::kPreview,
455 &preview_settings),
456 OK);
457
458 // Prepare preview requests.
459 std::vector<CaptureRequest> requests;
460 for (uint32_t i = 0; i < kNumPreviewRequests; i++) {
461 StreamBuffer preview_buffer = {
462 .stream_id = preview_config.streams[0].id,
463 .buffer_id = i,
464 .buffer = preview_buffers[i],
465 .status = BufferStatus::kOk,
466 .acquire_fence = nullptr,
467 .release_fence = nullptr,
468 };
469
470 CaptureRequest request = {
471 .frame_number = i,
472 .settings = HalCameraMetadata::Clone(preview_settings.get()),
473 .output_buffers = {preview_buffer},
474 };
475
476 requests.push_back(std::move(request));
477 }
478
479 ClearResultsAndMessages();
480 uint32_t num_processed_requests = 0;
481 ASSERT_EQ(session->ProcessCaptureRequest(requests, &num_processed_requests),
482 OK);
483 ASSERT_EQ(num_processed_requests, requests.size());
484
485 // Verify shutters and results are received.
486 for (auto& request : requests) {
487 EXPECT_EQ(WaitForShutter(request.frame_number, kCaptureTimeoutMs), OK);
488 EXPECT_EQ(WaitForResult(request, kCaptureTimeoutMs), OK);
489 }
490
491 allocator->FreeBuffers(&preview_buffers);
492 }
493
494 } // namespace
495 } // namespace google_camera_hal
496 } // namespace android
497