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_NDEBUG 0
18 #define LOG_TAG "GCH_CameraDevice"
19 #define ATRACE_TAG ATRACE_TAG_CAMERA
20 #include "camera_device.h"
21
22 #include <dlfcn.h>
23 #include <errno.h>
24 #include <log/log.h>
25 #include <meminfo/procmeminfo.h>
26 #include <stdio.h>
27 #include <sys/mman.h>
28 #include <sys/stat.h>
29 #include <utils/Trace.h>
30
31 #include <thread>
32
33 #include "hwl_types.h"
34 #include "log/log_main.h"
35 #include "utils.h"
36 #include "vendor_tags.h"
37
38 using android::meminfo::ProcMemInfo;
39 using namespace android::meminfo;
40
41 namespace android {
42 namespace {
43 enum class PreloadMode {
44 kMadvise = 0,
45 kMlockMadvise = 1,
46 };
47 } // namespace
48
MadviseFileForRange(size_t madvise_size_limit_bytes,size_t map_size_bytes,const uint8_t * map_begin,const uint8_t * map_end,const std::string & file_name,PreloadMode preload_mode)49 void MadviseFileForRange(size_t madvise_size_limit_bytes, size_t map_size_bytes,
50 const uint8_t* map_begin, const uint8_t* map_end,
51 const std::string& file_name,
52 PreloadMode preload_mode) {
53 // Ideal blockTransferSize for madvising files (128KiB)
54 static const size_t kIdealIoTransferSizeBytes = 128 * 1024;
55 size_t target_size_bytes =
56 std::min<size_t>(map_size_bytes, madvise_size_limit_bytes);
57 if (target_size_bytes == 0) {
58 return;
59 }
60 std::string trace_tag =
61 file_name + " size=" + std::to_string(target_size_bytes);
62 if (preload_mode == PreloadMode::kMadvise) {
63 trace_tag = "madvising " + trace_tag;
64 } else if (preload_mode == PreloadMode::kMlockMadvise) {
65 trace_tag = "madvising and mlocking " + trace_tag;
66 } else {
67 trace_tag = "Unknown preload mode " + trace_tag;
68 ALOGE("%s: Unknown preload mode %d", __FUNCTION__, preload_mode);
69 }
70 ATRACE_NAME(trace_tag.c_str());
71 // Based on requested size (target_size_bytes)
72 const uint8_t* target_pos = map_begin + target_size_bytes;
73
74 // Clamp endOfFile if its past map_end
75 if (target_pos > map_end) {
76 target_pos = map_end;
77 }
78
79 // Madvise the whole file up to target_pos in chunks of
80 // kIdealIoTransferSizeBytes (to MADV_WILLNEED)
81 // Note:
82 // madvise(MADV_WILLNEED) will prefetch max(fd readahead size, optimal
83 // block size for device) per call, hence the need for chunks. (128KB is a
84 // good default.)
85 for (const uint8_t* madvise_start = map_begin; madvise_start < target_pos;
86 madvise_start += kIdealIoTransferSizeBytes) {
87 void* madvise_addr =
88 const_cast<void*>(reinterpret_cast<const void*>(madvise_start));
89 size_t madvise_length =
90 std::min(kIdealIoTransferSizeBytes,
91 static_cast<size_t>(target_pos - madvise_start));
92 if (preload_mode == PreloadMode::kMlockMadvise) {
93 int status_mlock = mlock(madvise_addr, madvise_length);
94 // In case of error we stop mlocking rest of the file
95 if (status_mlock < 0) {
96 ALOGW(
97 "%s: Pinning memory by mlock failed! status=%i, errno=%i, "
98 "trace_tag=%s",
99 __FUNCTION__, status_mlock, errno, trace_tag.c_str());
100 break;
101 }
102 }
103 int status_madvise = madvise(madvise_addr, madvise_length, MADV_WILLNEED);
104 // In case of error we stop madvising rest of the file
105 if (status_madvise < 0) {
106 break;
107 }
108 }
109 }
110
ReadAheadVma(const Vma & vma,const size_t madvise_size_limit_bytes,PreloadMode preload_mode)111 static void ReadAheadVma(const Vma& vma, const size_t madvise_size_limit_bytes,
112 PreloadMode preload_mode) {
113 const uint8_t* map_begin = reinterpret_cast<uint8_t*>(vma.start);
114 const uint8_t* map_end = reinterpret_cast<uint8_t*>(vma.end);
115 MadviseFileForRange(madvise_size_limit_bytes,
116 static_cast<size_t>(map_end - map_begin), map_begin,
117 map_end, vma.name, preload_mode);
118 }
119
UnpinVma(const Vma & vma)120 static void UnpinVma(const Vma& vma) {
121 std::string trace_tag =
122 "munlocking " + vma.name + " size=" + std::to_string(vma.end - vma.start);
123 ATRACE_NAME(trace_tag.c_str());
124 int status_munlock =
125 munlock(reinterpret_cast<uint8_t*>(vma.start), vma.end - vma.start);
126 if (status_munlock < 0) {
127 ALOGW(
128 "%s: Unlocking memory failed! status=%i, errno=%i, "
129 "trace_tag=%s",
130 __FUNCTION__, status_munlock, errno, trace_tag.c_str());
131 }
132 }
133
134 // Update memory configuration to match the new configuration. This includes
135 // pinning new libraries, unpinning libraries that were pinned in the old
136 // config but aren't any longer, and madvising anonymous VMAs.
LoadLibraries(google_camera_hal::HwlMemoryConfig memory_config,google_camera_hal::HwlMemoryConfig old_memory_config)137 static void LoadLibraries(google_camera_hal::HwlMemoryConfig memory_config,
138 google_camera_hal::HwlMemoryConfig old_memory_config) {
139 auto vmaCollectorCb = [&memory_config, &old_memory_config](const Vma& vma) {
140 // Read ahead for anonymous VMAs and for specific files.
141 // vma.flags represents a VMAs rwx bits.
142 if (vma.inode == 0 && !vma.is_shared && vma.flags) {
143 if (memory_config.madvise_map_size_limit_bytes == 0) {
144 return true;
145 }
146 // Madvise anonymous memory, do not pin.
147 ReadAheadVma(vma, memory_config.madvise_map_size_limit_bytes,
148 PreloadMode::kMadvise);
149 return true;
150 }
151 if (memory_config.pinned_libraries.contains(vma.name) &&
152 !old_memory_config.pinned_libraries.contains(vma.name)) {
153 // File-backed VMAs do not have a madvise limit
154 ReadAheadVma(vma, std::numeric_limits<size_t>::max(),
155 PreloadMode::kMlockMadvise);
156 } else if (!memory_config.pinned_libraries.contains(vma.name) &&
157 old_memory_config.pinned_libraries.contains(vma.name)) {
158 // Unpin libraries that were previously pinned but are no longer needed.
159 ALOGI("%s: Unpinning %s", __FUNCTION__, vma.name.c_str());
160 UnpinVma(vma);
161 }
162 return true;
163 };
164 ProcMemInfo meminfo(getpid());
165 // TODO(b/376519437) - Restrict madvising to important VMAs.
166 meminfo.ForEachVmaFromMaps(vmaCollectorCb);
167 }
168
169 namespace google_camera_hal {
170
171 // HAL external capture session library path
172 #if GCH_HWL_USE_DLOPEN
173 #if defined(_LP64)
174 constexpr char kExternalCaptureSessionDir[] =
175 "/vendor/lib64/camera/capture_sessions/";
176 #else // defined(_LP64)
177 constexpr char kExternalCaptureSessionDir[] =
178 "/vendor/lib/camera/capture_sessions/";
179 #endif
180 #endif
181
182 HwlMemoryConfig CameraDevice::applied_memory_config_;
183 std::mutex CameraDevice::applied_memory_config_mutex_;
184
Create(std::unique_ptr<CameraDeviceHwl> camera_device_hwl,CameraBufferAllocatorHwl * camera_allocator_hwl)185 std::unique_ptr<CameraDevice> CameraDevice::Create(
186 std::unique_ptr<CameraDeviceHwl> camera_device_hwl,
187 CameraBufferAllocatorHwl* camera_allocator_hwl) {
188 ATRACE_CALL();
189 auto device = std::unique_ptr<CameraDevice>(new CameraDevice());
190
191 if (device == nullptr) {
192 ALOGE("%s: Creating CameraDevice failed.", __FUNCTION__);
193 return nullptr;
194 }
195
196 status_t res =
197 device->Initialize(std::move(camera_device_hwl), camera_allocator_hwl);
198 if (res != OK) {
199 ALOGE("%s: Initializing CameraDevice failed: %s (%d).", __FUNCTION__,
200 strerror(-res), res);
201 return nullptr;
202 }
203
204 ALOGI("%s: Created a camera device for public(%u)", __FUNCTION__,
205 device->GetPublicCameraId());
206
207 android::google_camera_hal::HwlMemoryConfig memory_config =
208 device->camera_device_hwl_->GetMemoryConfig();
209 memory_config.madvise_map_size_limit_bytes = 0;
210 ALOGI("Pinning memory for %zu shared libraries.",
211 memory_config.pinned_libraries.size());
212
213 std::lock_guard<std::mutex> lock(applied_memory_config_mutex_);
214 std::thread t(LoadLibraries, memory_config, device->GetAppliedMemoryConfig());
215 t.detach();
216 device->SetAppliedMemoryConfig(memory_config);
217
218 return device;
219 }
220
Initialize(std::unique_ptr<CameraDeviceHwl> camera_device_hwl,CameraBufferAllocatorHwl * camera_allocator_hwl)221 status_t CameraDevice::Initialize(
222 std::unique_ptr<CameraDeviceHwl> camera_device_hwl,
223 CameraBufferAllocatorHwl* camera_allocator_hwl) {
224 ATRACE_CALL();
225 if (camera_device_hwl == nullptr) {
226 ALOGE("%s: camera_device_hwl cannot be nullptr.", __FUNCTION__);
227 return BAD_VALUE;
228 }
229
230 public_camera_id_ = camera_device_hwl->GetCameraId();
231 camera_device_hwl_ = std::move(camera_device_hwl);
232 camera_allocator_hwl_ = camera_allocator_hwl;
233 status_t res = LoadExternalCaptureSession();
234 if (res != OK) {
235 ALOGE("%s: Loading external capture sessions failed: %s(%d)", __FUNCTION__,
236 strerror(-res), res);
237 return res;
238 }
239
240 std::unique_ptr<HalCameraMetadata> static_metadata;
241 res = camera_device_hwl_->GetCameraCharacteristics(&static_metadata);
242 if (res != OK) {
243 ALOGE("%s: Getting camera characteristics failed: %s(%d)", __FUNCTION__,
244 strerror(-res), res);
245 return res;
246 }
247
248 res = utils::GetStreamUseCases(
249 static_metadata.get(),
250 &camera_id_to_stream_use_cases_[camera_device_hwl_->GetCameraId()]);
251 if (res != OK) {
252 ALOGE(
253 "%s: Initializing logical stream use case for camera id %u failed: "
254 "%s(%d)",
255 __FUNCTION__, camera_device_hwl_->GetCameraId(), strerror(-res), res);
256 return res;
257 }
258 res = utils::GetPhysicalCameraStreamUseCases(camera_device_hwl_.get(),
259 &camera_id_to_stream_use_cases_);
260
261 if (res != OK) {
262 ALOGE(
263 "%s: Initializing physical stream use case for camera id %u failed: "
264 "%s(%d)",
265 __FUNCTION__, camera_device_hwl_->GetCameraId(), strerror(-res), res);
266 }
267 return res;
268 }
269
GetResourceCost(CameraResourceCost * cost)270 status_t CameraDevice::GetResourceCost(CameraResourceCost* cost) {
271 ATRACE_CALL();
272 return camera_device_hwl_->GetResourceCost(cost);
273 }
274
GetCameraCharacteristics(std::unique_ptr<HalCameraMetadata> * characteristics)275 status_t CameraDevice::GetCameraCharacteristics(
276 std::unique_ptr<HalCameraMetadata>* characteristics) {
277 ATRACE_CALL();
278 status_t res = camera_device_hwl_->GetCameraCharacteristics(characteristics);
279 if (res != OK) {
280 ALOGE("%s: GetCameraCharacteristics() failed: %s (%d).", __FUNCTION__,
281 strerror(-res), res);
282 return res;
283 }
284
285 return hal_vendor_tag_utils::ModifyCharacteristicsKeys(characteristics->get());
286 }
287
288 // Populates the required session characteristics keys from a camera
289 // characteristics object.
generateSessionCharacteristics(const HalCameraMetadata * camera_characteristics,HalCameraMetadata * session_characteristics)290 status_t generateSessionCharacteristics(
291 const HalCameraMetadata* camera_characteristics,
292 HalCameraMetadata* session_characteristics) {
293 if (camera_characteristics == nullptr) {
294 ALOGE("%s: camera characteristics is nullptr", __FUNCTION__);
295 return BAD_VALUE;
296 }
297
298 if (session_characteristics == nullptr) {
299 ALOGE("%s: session characteristics is nullptr", __FUNCTION__);
300 return BAD_VALUE;
301 }
302
303 camera_metadata_ro_entry entry;
304 status_t res;
305
306 // Get the zoom ratio key
307 res = camera_characteristics->Get(ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry);
308 if (res == OK && entry.count == 2) {
309 std::vector<float> zoom_ratio_key(entry.data.f, entry.data.f + entry.count);
310 if (session_characteristics->Set(ANDROID_CONTROL_ZOOM_RATIO_RANGE,
311 zoom_ratio_key.data(),
312 zoom_ratio_key.size()) != OK) {
313 ALOGE("%s Updating static metadata with zoom ratio range failed",
314 __FUNCTION__);
315 return UNKNOWN_ERROR;
316 }
317 }
318
319 // Get the max digital zoom key
320 res = camera_characteristics->Get(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,
321 &entry);
322 if (res == OK) {
323 std::vector<float> max_digital_zoom_key(entry.data.f,
324 entry.data.f + entry.count);
325 if (session_characteristics->Set(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,
326 max_digital_zoom_key.data(),
327 max_digital_zoom_key.size()) != OK) {
328 ALOGE("%s Updating static metadata with max digital zoom failed",
329 __FUNCTION__);
330 return UNKNOWN_ERROR;
331 }
332 }
333
334 return OK;
335 }
336
GetSessionCharacteristics(const StreamConfiguration & stream_config,std::unique_ptr<HalCameraMetadata> & session_characteristics)337 status_t CameraDevice::GetSessionCharacteristics(
338 const StreamConfiguration& stream_config,
339 std::unique_ptr<HalCameraMetadata>& session_characteristics) {
340 ATRACE_CALL();
341 std::unique_ptr<HalCameraMetadata> camera_characteristics;
342 status_t res = camera_device_hwl_->GetSessionCharacteristics(
343 stream_config, camera_characteristics);
344 if (res != OK) {
345 ALOGE("%s: GetCameraCharacteristics() failed: %s (%d).", __FUNCTION__,
346 strerror(-res), res);
347 return res;
348 }
349
350 // Allocating space for 10 entries and 256 bytes.
351 session_characteristics = HalCameraMetadata::Create(10, 256);
352
353 return generateSessionCharacteristics(camera_characteristics.get(),
354 session_characteristics.get());
355 }
356
GetPhysicalCameraCharacteristics(uint32_t physical_camera_id,std::unique_ptr<HalCameraMetadata> * characteristics)357 status_t CameraDevice::GetPhysicalCameraCharacteristics(
358 uint32_t physical_camera_id,
359 std::unique_ptr<HalCameraMetadata>* characteristics) {
360 ATRACE_CALL();
361 status_t res = camera_device_hwl_->GetPhysicalCameraCharacteristics(
362 physical_camera_id, characteristics);
363 if (res != OK) {
364 ALOGE("%s: GetPhysicalCameraCharacteristics() failed: %s (%d).",
365 __FUNCTION__, strerror(-res), res);
366 return res;
367 }
368
369 return hal_vendor_tag_utils::ModifyCharacteristicsKeys(characteristics->get());
370 }
371
SetTorchMode(TorchMode mode)372 status_t CameraDevice::SetTorchMode(TorchMode mode) {
373 ATRACE_CALL();
374 return camera_device_hwl_->SetTorchMode(mode);
375 }
376
TurnOnTorchWithStrengthLevel(int32_t torch_strength)377 status_t CameraDevice::TurnOnTorchWithStrengthLevel(int32_t torch_strength) {
378 ATRACE_CALL();
379 return camera_device_hwl_->TurnOnTorchWithStrengthLevel(torch_strength);
380 }
381
GetTorchStrengthLevel(int32_t & torch_strength) const382 status_t CameraDevice::GetTorchStrengthLevel(int32_t& torch_strength) const {
383 ATRACE_CALL();
384 status_t res = camera_device_hwl_->GetTorchStrengthLevel(torch_strength);
385 if (res != OK) {
386 ALOGE("%s: GetTorchStrengthLevel() failed: %s (%d).", __FUNCTION__,
387 strerror(-res), res);
388 return res;
389 }
390
391 return res;
392 }
393
ConstructDefaultRequestSettings(RequestTemplate type,std::unique_ptr<HalCameraMetadata> * request_settings)394 status_t CameraDevice::ConstructDefaultRequestSettings(
395 RequestTemplate type, std::unique_ptr<HalCameraMetadata>* request_settings) {
396 ATRACE_CALL();
397 return camera_device_hwl_->ConstructDefaultRequestSettings(type,
398 request_settings);
399 }
400
DumpState(int fd)401 status_t CameraDevice::DumpState(int fd) {
402 ATRACE_CALL();
403 return camera_device_hwl_->DumpState(fd);
404 }
405
CreateCameraDeviceSession(std::unique_ptr<CameraDeviceSession> * session)406 status_t CameraDevice::CreateCameraDeviceSession(
407 std::unique_ptr<CameraDeviceSession>* session) {
408 ATRACE_CALL();
409 if (session == nullptr) {
410 ALOGE("%s: session is nullptr.", __FUNCTION__);
411 return BAD_VALUE;
412 }
413
414 std::unique_ptr<CameraDeviceSessionHwl> session_hwl;
415 status_t res = camera_device_hwl_->CreateCameraDeviceSessionHwl(
416 camera_allocator_hwl_, &session_hwl);
417 if (res != OK) {
418 ALOGE("%s: Creating a CameraDeviceSessionHwl failed: %s(%d)", __FUNCTION__,
419 strerror(-res), res);
420 return res;
421 }
422
423 *session = CameraDeviceSession::Create(std::move(session_hwl),
424 external_session_factory_entries_,
425 camera_allocator_hwl_);
426 if (*session == nullptr) {
427 ALOGE("%s: Creating a CameraDeviceSession failed: %s(%d)", __FUNCTION__,
428 strerror(-res), res);
429 return UNKNOWN_ERROR;
430 }
431
432 std::lock_guard<std::mutex> lock(applied_memory_config_mutex_);
433 HwlMemoryConfig memory_config = camera_device_hwl_->GetMemoryConfig();
434 std::thread t(LoadLibraries, memory_config, GetAppliedMemoryConfig());
435 SetAppliedMemoryConfig(memory_config);
436 t.detach();
437
438 return OK;
439 }
440
IsStreamCombinationSupported(const StreamConfiguration & stream_config,bool check_settings)441 bool CameraDevice::IsStreamCombinationSupported(
442 const StreamConfiguration& stream_config, bool check_settings) {
443 if (!utils::IsStreamUseCaseSupported(stream_config, public_camera_id_,
444 camera_id_to_stream_use_cases_)) {
445 return false;
446 }
447
448 bool supported = camera_device_hwl_->IsStreamCombinationSupported(
449 stream_config, check_settings);
450 if (!supported) {
451 ALOGD("%s: stream config is not supported.", __FUNCTION__);
452 }
453
454 return supported;
455 }
456
LoadExternalCaptureSession()457 status_t CameraDevice::LoadExternalCaptureSession() {
458 ATRACE_CALL();
459
460 if (external_session_factory_entries_.size() > 0) {
461 ALOGI("%s: External capture session libraries already loaded; skip.",
462 __FUNCTION__);
463 return OK;
464 }
465
466 #if GCH_HWL_USE_DLOPEN
467 for (const auto& lib_path :
468 utils::FindLibraryPaths(kExternalCaptureSessionDir)) {
469 ALOGI("%s: Loading %s", __FUNCTION__, lib_path.c_str());
470 void* lib_handle = nullptr;
471 // load shared library and never unload
472 // TODO(b/...): Switch to using build-system based HWL
473 // loading and remove dlopen here?
474 lib_handle = dlopen(lib_path.c_str(), RTLD_NOW);
475 if (lib_handle == nullptr) {
476 ALOGW("Failed loading %s.", lib_path.c_str());
477 continue;
478 }
479
480 GetCaptureSessionFactoryFunc external_session_factory_t =
481 reinterpret_cast<GetCaptureSessionFactoryFunc>(
482 dlsym(lib_handle, "GetCaptureSessionFactory"));
483 if (external_session_factory_t == nullptr) {
484 ALOGE("%s: dlsym failed (%s) when loading %s.", __FUNCTION__,
485 "GetCaptureSessionFactory", lib_path.c_str());
486 dlclose(lib_handle);
487 lib_handle = nullptr;
488 continue;
489 }
490
491 external_session_factory_entries_.push_back(external_session_factory_t);
492 external_capture_session_lib_handles_.push_back(lib_handle);
493 }
494 #else
495 if (GetCaptureSessionFactory) {
496 external_session_factory_entries_.push_back(GetCaptureSessionFactory);
497 }
498 #endif
499
500 return OK;
501 }
502
~CameraDevice()503 CameraDevice::~CameraDevice() {
504 }
505
GetProfiler(uint32_t camera_id,int option)506 std::unique_ptr<google::camera_common::Profiler> CameraDevice::GetProfiler(
507 uint32_t camera_id, int option) {
508 return camera_device_hwl_->GetProfiler(camera_id, option);
509 }
510
511 } // namespace google_camera_hal
512 } // namespace android
513