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