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