• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 "ConfigManager.h"
18 
19 #include <hardware/gralloc.h>
20 #include <utils/SystemClock.h>
21 
22 #include <fstream>
23 #include <sstream>
24 #include <string_view>
25 #include <thread>
26 
27 namespace {
28 
29 using ::aidl::android::hardware::automotive::evs::CameraParam;
30 using ::aidl::android::hardware::graphics::common::PixelFormat;
31 using ::tinyxml2::XMLAttribute;
32 using ::tinyxml2::XMLDocument;
33 using ::tinyxml2::XMLElement;
34 
35 }  // namespace
36 
37 std::string_view ConfigManager::sConfigDefaultPath =
38         "/vendor/etc/automotive/evs/evs_aidl_hal_configuration.xml";
39 std::string_view ConfigManager::sConfigOverridePath =
40         "/vendor/etc/automotive/evs/evs_configuration_override.xml";
41 
printElementNames(const XMLElement * rootElem,std::string prefix) const42 void ConfigManager::printElementNames(const XMLElement* rootElem, std::string prefix) const {
43     const XMLElement* curElem = rootElem;
44 
45     while (curElem != nullptr) {
46         LOG(VERBOSE) << "[ELEM] " << prefix << curElem->Name();
47         const XMLAttribute* curAttr = curElem->FirstAttribute();
48         while (curAttr) {
49             LOG(VERBOSE) << "[ATTR] " << prefix << curAttr->Name() << ": " << curAttr->Value();
50             curAttr = curAttr->Next();
51         }
52 
53         /* recursively go down to descendants */
54         printElementNames(curElem->FirstChildElement(), prefix + "\t");
55 
56         curElem = curElem->NextSiblingElement();
57     }
58 }
59 
readCameraInfo(const XMLElement * const aCameraElem)60 void ConfigManager::readCameraInfo(const XMLElement* const aCameraElem) {
61     if (aCameraElem == nullptr) {
62         LOG(WARNING) << "XML file does not have required camera element";
63         return;
64     }
65 
66     const XMLElement* curElem = aCameraElem->FirstChildElement();
67     while (curElem != nullptr) {
68         if (!strcmp(curElem->Name(), "group")) {
69             /* camera group identifier */
70             const char* id = curElem->FindAttribute("id")->Value();
71 
72             /* create a camera group to be filled */
73             CameraGroupInfo* aCamera = new CameraGroupInfo();
74 
75             /* read camera device information */
76             if (!readCameraDeviceInfo(aCamera, curElem)) {
77                 LOG(WARNING) << "Failed to read a camera information of " << id;
78                 delete aCamera;
79                 continue;
80             }
81 
82             /* camera group synchronization */
83             const char* sync = curElem->FindAttribute("synchronized")->Value();
84             if (!strcmp(sync, "CALIBRATED")) {
85                 aCamera->synchronized = ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_CALIBRATED;
86             } else if (!strcmp(sync, "APPROXIMATE")) {
87                 aCamera->synchronized = ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_APPROXIMATE;
88             } else {
89                 aCamera->synchronized = 0;  // Not synchronized
90             }
91 
92             /* add a group to hash map */
93             mCameraGroups.insert_or_assign(id, std::unique_ptr<CameraGroupInfo>(aCamera));
94         } else if (!std::strcmp(curElem->Name(), "device")) {
95             /* camera unique identifier */
96             const char* id = curElem->FindAttribute("id")->Value();
97 
98             /* camera mount location */
99             const char* pos = curElem->FindAttribute("position")->Value();
100 
101             /* create a camera device to be filled */
102             CameraInfo* aCamera = new CameraInfo();
103 
104             /* read camera device information */
105             if (!readCameraDeviceInfo(aCamera, curElem)) {
106                 LOG(WARNING) << "Failed to read a camera information of " << id;
107                 delete aCamera;
108                 continue;
109             }
110 
111             /* store read camera module information */
112             mCameraInfo.insert_or_assign(id, std::unique_ptr<CameraInfo>(aCamera));
113 
114             /* assign a camera device to a position group */
115             mCameraPosition[pos].insert(std::move(id));
116         } else {
117             /* ignore other device types */
118             LOG(DEBUG) << "Unknown element " << curElem->Name() << " is ignored";
119         }
120 
121         curElem = curElem->NextSiblingElement();
122     }
123 }
124 
readCameraDeviceInfo(CameraInfo * aCamera,const XMLElement * aDeviceElem)125 bool ConfigManager::readCameraDeviceInfo(CameraInfo* aCamera, const XMLElement* aDeviceElem) {
126     if (aCamera == nullptr || aDeviceElem == nullptr) {
127         return false;
128     }
129 
130     /* size information to allocate camera_metadata_t */
131     size_t totalEntries = 0;
132     size_t totalDataSize = 0;
133 
134     /* read device capabilities */
135     totalEntries +=
136             readCameraCapabilities(aDeviceElem->FirstChildElement("caps"), aCamera, totalDataSize);
137 
138     /* read camera metadata */
139     totalEntries += readCameraMetadata(aDeviceElem->FirstChildElement("characteristics"), aCamera,
140                                        totalDataSize);
141 
142     /* construct camera_metadata_t */
143     if (!constructCameraMetadata(aCamera, totalEntries, totalDataSize)) {
144         LOG(WARNING) << "Either failed to allocate memory or "
145                      << "allocated memory was not large enough";
146     }
147 
148     return true;
149 }
150 
readCameraCapabilities(const XMLElement * const aCapElem,CameraInfo * aCamera,size_t & dataSize)151 size_t ConfigManager::readCameraCapabilities(const XMLElement* const aCapElem, CameraInfo* aCamera,
152                                              size_t& dataSize) {
153     if (aCapElem == nullptr || aCamera == nullptr) {
154         return 0;
155     }
156 
157     std::string token;
158     const XMLElement* curElem = nullptr;
159 
160     /* a list of supported camera parameters/controls */
161     curElem = aCapElem->FirstChildElement("supported_controls");
162     if (curElem != nullptr) {
163         const XMLElement* ctrlElem = curElem->FirstChildElement("control");
164         while (ctrlElem != nullptr) {
165             const char* nameAttr = ctrlElem->FindAttribute("name")->Value();
166             const int32_t minVal = std::stoi(ctrlElem->FindAttribute("min")->Value());
167             const int32_t maxVal = std::stoi(ctrlElem->FindAttribute("max")->Value());
168 
169             int32_t stepVal = 1;
170             const XMLAttribute* stepAttr = ctrlElem->FindAttribute("step");
171             if (stepAttr != nullptr) {
172                 stepVal = std::stoi(stepAttr->Value());
173             }
174 
175             CameraParam aParam;
176             if (ConfigManagerUtil::convertToEvsCameraParam(nameAttr, aParam)) {
177                 aCamera->controls.insert_or_assign(aParam,
178                                                    std::move(std::make_tuple(minVal, maxVal,
179                                                                              stepVal)));
180             }
181 
182             ctrlElem = ctrlElem->NextSiblingElement("control");
183         }
184     }
185 
186     /* a list of camera stream configurations */
187     curElem = aCapElem->FirstChildElement("stream");
188     while (curElem != nullptr) {
189         /* read 5 attributes */
190         const XMLAttribute* idAttr = curElem->FindAttribute("id");
191         const XMLAttribute* widthAttr = curElem->FindAttribute("width");
192         const XMLAttribute* heightAttr = curElem->FindAttribute("height");
193         const XMLAttribute* fmtAttr = curElem->FindAttribute("format");
194         const XMLAttribute* fpsAttr = curElem->FindAttribute("framerate");
195 
196         const int32_t id = std::stoi(idAttr->Value());
197         int32_t framerate = 0;
198         if (fpsAttr != nullptr) {
199             framerate = std::stoi(fpsAttr->Value());
200         }
201 
202         PixelFormat format = PixelFormat::UNSPECIFIED;
203         if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(), format)) {
204             StreamConfiguration cfg = {
205                     .id = id,
206                     .width = std::stoi(widthAttr->Value()),
207                     .height = std::stoi(heightAttr->Value()),
208                     .format = format,
209                     .type = ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
210                     .framerate = framerate,
211             };
212             aCamera->streamConfigurations.insert_or_assign(id, cfg);
213         }
214 
215         curElem = curElem->NextSiblingElement("stream");
216     }
217 
218     dataSize = calculate_camera_metadata_entry_data_size(
219             get_camera_metadata_tag_type(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS),
220             aCamera->streamConfigurations.size() * sizeof(StreamConfiguration));
221 
222     /* a single camera metadata entry contains multiple stream configurations */
223     return dataSize > 0 ? 1 : 0;
224 }
225 
readCameraMetadata(const XMLElement * const aParamElem,CameraInfo * aCamera,size_t & dataSize)226 size_t ConfigManager::readCameraMetadata(const XMLElement* const aParamElem, CameraInfo* aCamera,
227                                          size_t& dataSize) {
228     if (aParamElem == nullptr || aCamera == nullptr) {
229         return 0;
230     }
231 
232     const XMLElement* curElem = aParamElem->FirstChildElement("parameter");
233     size_t numEntries = 0;
234     camera_metadata_tag_t tag;
235     while (curElem != nullptr) {
236         if (ConfigManagerUtil::convertToMetadataTag(curElem->FindAttribute("name")->Value(), tag)) {
237             switch (tag) {
238                 case ANDROID_LENS_DISTORTION:
239                 case ANDROID_LENS_POSE_ROTATION:
240                 case ANDROID_LENS_POSE_TRANSLATION:
241                 case ANDROID_LENS_INTRINSIC_CALIBRATION: {
242                     /* float[] */
243                     size_t count = 0;
244                     void* data =
245                             ConfigManagerUtil::convertFloatArray(curElem->FindAttribute("size")
246                                                                          ->Value(),
247                                                                  curElem->FindAttribute("value")
248                                                                          ->Value(),
249                                                                  count);
250 
251                     aCamera->cameraMetadata.insert_or_assign(tag, std::make_pair(data, count));
252 
253                     ++numEntries;
254                     dataSize +=
255                             calculate_camera_metadata_entry_data_size(get_camera_metadata_tag_type(
256                                                                               tag),
257                                                                       count);
258 
259                     break;
260                 }
261 
262                 case ANDROID_REQUEST_AVAILABLE_CAPABILITIES: {
263                     camera_metadata_enum_android_request_available_capabilities_t* data =
264                             new camera_metadata_enum_android_request_available_capabilities_t[1];
265                     if (ConfigManagerUtil::convertToCameraCapability(curElem->FindAttribute("value")
266                                                                              ->Value(),
267                                                                      *data)) {
268                         aCamera->cameraMetadata.insert_or_assign(tag,
269                                                                  std::make_pair((void*)data, 1));
270 
271                         ++numEntries;
272                         dataSize += calculate_camera_metadata_entry_data_size(
273                                 get_camera_metadata_tag_type(tag), 1);
274                     }
275                     break;
276                 }
277 
278                 case ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS: {
279                     /* a comma-separated list of physical camera devices */
280                     size_t len = strlen(curElem->FindAttribute("value")->Value());
281                     char* data = new char[len + 1];
282                     memcpy(data, curElem->FindAttribute("value")->Value(), len * sizeof(char));
283 
284                     /* replace commas with null char */
285                     char* p = data;
286                     while (*p != '\0') {
287                         if (*p == ',') {
288                             *p = '\0';
289                         }
290                         ++p;
291                     }
292 
293                     aCamera->cameraMetadata.insert_or_assign(tag,
294                                                              std::make_pair((void*)data, len + 1));
295 
296                     ++numEntries;
297                     dataSize +=
298                             calculate_camera_metadata_entry_data_size(get_camera_metadata_tag_type(
299                                                                               tag),
300                                                                       len);
301                     break;
302                 }
303 
304                 /* TODO(b/140416878): add vendor-defined/custom tag support */
305                 default:
306                     LOG(WARNING) << "Parameter " << curElem->FindAttribute("name")->Value()
307                                  << " is not supported";
308                     break;
309             }
310         } else {
311             LOG(WARNING) << "Unsupported metadata tag " << curElem->FindAttribute("name")->Value()
312                          << " is found.";
313         }
314 
315         curElem = curElem->NextSiblingElement("parameter");
316     }
317 
318     return numEntries;
319 }
320 
constructCameraMetadata(CameraInfo * aCamera,size_t totalEntries,size_t totalDataSize)321 bool ConfigManager::constructCameraMetadata(CameraInfo* aCamera, size_t totalEntries,
322                                             size_t totalDataSize) {
323     if (aCamera == nullptr || !aCamera->allocate(totalEntries, totalDataSize)) {
324         LOG(ERROR) << "Failed to allocate memory for camera metadata";
325         return false;
326     }
327 
328     const size_t numStreamConfigs = aCamera->streamConfigurations.size();
329     std::unique_ptr<int32_t[]> data(new int32_t[sizeof(StreamConfiguration) * numStreamConfigs]);
330     int32_t* ptr = data.get();
331     for (auto& cfg : aCamera->streamConfigurations) {
332         memcpy(ptr, &cfg.second, sizeof(StreamConfiguration));
333         ptr += sizeof(StreamConfiguration);
334     }
335     int32_t err =
336             add_camera_metadata_entry(aCamera->characteristics,
337                                       ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, data.get(),
338                                       numStreamConfigs * sizeof(StreamConfiguration));
339 
340     if (err) {
341         LOG(ERROR) << "Failed to add stream configurations to metadata, ignored";
342         return false;
343     }
344 
345     bool success = true;
346     for (auto& [tag, entry] : aCamera->cameraMetadata) {
347         /* try to add new camera metadata entry */
348         int32_t err =
349                 add_camera_metadata_entry(aCamera->characteristics, tag, entry.first, entry.second);
350         if (err) {
351             LOG(ERROR) << "Failed to add an entry with a tag, " << std::hex << tag;
352 
353             /* may exceed preallocated capacity */
354             LOG(ERROR) << "Camera metadata has "
355                        << get_camera_metadata_entry_count(aCamera->characteristics) << " / "
356                        << get_camera_metadata_entry_capacity(aCamera->characteristics)
357                        << " entries and "
358                        << get_camera_metadata_data_count(aCamera->characteristics) << " / "
359                        << get_camera_metadata_data_capacity(aCamera->characteristics)
360                        << " bytes are filled.";
361             LOG(ERROR) << "\tCurrent metadata entry requires "
362                        << calculate_camera_metadata_entry_data_size(tag, entry.second) << " bytes.";
363 
364             success = false;
365         }
366     }
367 
368     LOG(VERBOSE) << "Camera metadata has "
369                  << get_camera_metadata_entry_count(aCamera->characteristics) << " / "
370                  << get_camera_metadata_entry_capacity(aCamera->characteristics) << " entries and "
371                  << get_camera_metadata_data_count(aCamera->characteristics) << " / "
372                  << get_camera_metadata_data_capacity(aCamera->characteristics)
373                  << " bytes are filled.";
374     return success;
375 }
376 
readSystemInfo(const XMLElement * const aSysElem)377 void ConfigManager::readSystemInfo(const XMLElement* const aSysElem) {
378     if (aSysElem == nullptr) {
379         return;
380     }
381 
382     /*
383      * Please note that this function assumes that a given system XML element
384      * and its child elements follow DTD.  If it does not, it will cause a
385      * segmentation fault due to the failure of finding expected attributes.
386      */
387 
388     /* read number of cameras available in the system */
389     const XMLElement* xmlElem = aSysElem->FirstChildElement("num_cameras");
390     if (xmlElem != nullptr) {
391         mSystemInfo.numCameras = std::stoi(xmlElem->FindAttribute("value")->Value());
392     }
393 }
394 
readDisplayInfo(const XMLElement * const aDisplayElem)395 void ConfigManager::readDisplayInfo(const XMLElement* const aDisplayElem) {
396     if (aDisplayElem == nullptr) {
397         LOG(WARNING) << "XML file does not have required camera element";
398         return;
399     }
400 
401     const XMLElement* curDev = aDisplayElem->FirstChildElement("device");
402     while (curDev != nullptr) {
403         const char* id = curDev->FindAttribute("id")->Value();
404         std::unique_ptr<DisplayInfo> dpy(new DisplayInfo());
405         if (dpy == nullptr) {
406             LOG(ERROR) << "Failed to allocate memory for DisplayInfo";
407             return;
408         }
409 
410         const XMLElement* cap = curDev->FirstChildElement("caps");
411         if (cap != nullptr) {
412             const XMLElement* curStream = cap->FirstChildElement("stream");
413             while (curStream != nullptr) {
414                 /* read 4 attributes */
415                 const XMLAttribute* idAttr = curStream->FindAttribute("id");
416                 const XMLAttribute* widthAttr = curStream->FindAttribute("width");
417                 const XMLAttribute* heightAttr = curStream->FindAttribute("height");
418                 const XMLAttribute* fmtAttr = curStream->FindAttribute("format");
419 
420                 const int32_t id = std::stoi(idAttr->Value());
421                 PixelFormat format = PixelFormat::UNSPECIFIED;
422                 if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(), format)) {
423                     StreamConfiguration cfg = {
424                             .id = id,
425                             .width = std::stoi(widthAttr->Value()),
426                             .height = std::stoi(heightAttr->Value()),
427                             .format = format,
428                             .type = ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT,
429                     };
430                     dpy->streamConfigurations.insert_or_assign(id, cfg);
431                 }
432 
433                 curStream = curStream->NextSiblingElement("stream");
434             }
435         }
436 
437         mDisplayInfo.insert_or_assign(id, std::move(dpy));
438         curDev = curDev->NextSiblingElement("device");
439     }
440 
441     return;
442 }
443 
readConfigDataFromXML()444 bool ConfigManager::readConfigDataFromXML() noexcept {
445     XMLDocument xmlDoc;
446 
447     const int64_t parsingStart = android::elapsedRealtimeNano();
448 
449     /* load and parse a configuration file */
450     xmlDoc.LoadFile(sConfigOverridePath.data());
451     if (xmlDoc.ErrorID() != tinyxml2::XML_SUCCESS) {
452         xmlDoc.LoadFile(sConfigDefaultPath.data());
453         if (xmlDoc.ErrorID() != tinyxml2::XML_SUCCESS) {
454             LOG(ERROR) << "Failed to load and/or parse a configuration file, " << xmlDoc.ErrorStr();
455             return false;
456         }
457     }
458 
459     /* retrieve the root element */
460     const XMLElement* rootElem = xmlDoc.RootElement();
461     if (std::strcmp(rootElem->Name(), "configuration")) {
462         LOG(ERROR) << "A configuration file is not in the required format.  "
463                    << "See /etc/automotive/evs/evs_configuration.dtd";
464         return false;
465     }
466 
467     std::unique_lock<std::mutex> lock(mConfigLock);
468 
469     /*
470      * parse camera information; this needs to be done before reading system
471      * information
472      */
473     readCameraInfo(rootElem->FirstChildElement("camera"));
474 
475     /* parse system information */
476     readSystemInfo(rootElem->FirstChildElement("system"));
477 
478     /* parse display information */
479     readDisplayInfo(rootElem->FirstChildElement("display"));
480 
481     /* configuration data is ready to be consumed */
482     mIsReady = true;
483 
484     /* notify that configuration data is ready */
485     lock.unlock();
486     mConfigCond.notify_all();
487 
488     const int64_t parsingEnd = android::elapsedRealtimeNano();
489     LOG(INFO) << "Parsing configuration file takes " << std::scientific
490               << (double)(parsingEnd - parsingStart) / 1000000.0 << " ms.";
491 
492     return true;
493 }
494 
readConfigDataFromBinary()495 bool ConfigManager::readConfigDataFromBinary() {
496     /* Temporary buffer to hold configuration data read from a binary file */
497     char mBuffer[1024];
498 
499     std::fstream srcFile;
500     const int64_t readStart = android::elapsedRealtimeNano();
501 
502     srcFile.open(mBinaryFilePath, std::fstream::in | std::fstream::binary);
503     if (!srcFile) {
504         LOG(ERROR) << "Failed to open a source binary file, " << mBinaryFilePath;
505         return false;
506     }
507 
508     std::unique_lock<std::mutex> lock(mConfigLock);
509     mIsReady = false;
510 
511     /* read configuration data into the internal buffer */
512     srcFile.read(mBuffer, sizeof(mBuffer));
513     LOG(VERBOSE) << __FUNCTION__ << ": " << srcFile.gcount() << " bytes are read.";
514     char* p = mBuffer;
515     size_t sz = 0;
516 
517     /* read number of camera group information entries */
518     const size_t ngrps = *(reinterpret_cast<size_t*>(p));
519     p += sizeof(size_t);
520 
521     /* read each camera information entry */
522     for (size_t cidx = 0; cidx < ngrps; ++cidx) {
523         /* read camera identifier */
524         std::string cameraId = *(reinterpret_cast<std::string*>(p));
525         p += sizeof(std::string);
526 
527         /* size of camera_metadata_t */
528         const size_t num_entry = *(reinterpret_cast<size_t*>(p));
529         p += sizeof(size_t);
530         const size_t num_data = *(reinterpret_cast<size_t*>(p));
531         p += sizeof(size_t);
532 
533         /* create CameraInfo and add it to hash map */
534         std::unique_ptr<ConfigManager::CameraGroupInfo> aCamera;
535         if (aCamera == nullptr || !aCamera->allocate(num_entry, num_data)) {
536             LOG(ERROR) << "Failed to create new CameraInfo object";
537             mCameraInfo.clear();
538             return false;
539         }
540 
541         /* controls */
542         typedef struct {
543             CameraParam cid;
544             int32_t min;
545             int32_t max;
546             int32_t step;
547         } CameraCtrl;
548         sz = *(reinterpret_cast<size_t*>(p));
549         p += sizeof(size_t);
550         CameraCtrl* ptr = reinterpret_cast<CameraCtrl*>(p);
551         for (size_t idx = 0; idx < sz; ++idx) {
552             CameraCtrl temp = *ptr++;
553             aCamera->controls.insert_or_assign(temp.cid,
554                                                std::move(std::make_tuple(temp.min, temp.max,
555                                                                          temp.step)));
556         }
557         p = reinterpret_cast<char*>(ptr);
558 
559         /* stream configurations */
560         sz = *(reinterpret_cast<size_t*>(p));
561         p += sizeof(size_t);
562         int32_t* i32_ptr = reinterpret_cast<int32_t*>(p);
563         for (size_t idx = 0; idx < sz; ++idx) {
564             const int32_t id = *i32_ptr++;
565 
566             StreamConfiguration temp;
567             memcpy(&temp, i32_ptr, sizeof(StreamConfiguration));
568             i32_ptr += sizeof(StreamConfiguration);
569             aCamera->streamConfigurations.insert_or_assign(id, temp);
570         }
571         p = reinterpret_cast<char*>(i32_ptr);
572 
573         /* synchronization */
574         aCamera->synchronized = *(reinterpret_cast<int32_t*>(p));
575         p += sizeof(int32_t);
576 
577         for (size_t idx = 0; idx < num_entry; ++idx) {
578             /* Read camera metadata entries */
579             camera_metadata_tag_t tag = *reinterpret_cast<camera_metadata_tag_t*>(p);
580             p += sizeof(camera_metadata_tag_t);
581             const size_t count = *reinterpret_cast<size_t*>(p);
582             p += sizeof(size_t);
583 
584             const int32_t type = get_camera_metadata_tag_type(tag);
585             switch (type) {
586                 case TYPE_BYTE: {
587                     add_camera_metadata_entry(aCamera->characteristics, tag, p, count);
588                     p += count * sizeof(uint8_t);
589                     break;
590                 }
591                 case TYPE_INT32: {
592                     add_camera_metadata_entry(aCamera->characteristics, tag, p, count);
593                     p += count * sizeof(int32_t);
594                     break;
595                 }
596                 case TYPE_FLOAT: {
597                     add_camera_metadata_entry(aCamera->characteristics, tag, p, count);
598                     p += count * sizeof(float);
599                     break;
600                 }
601                 case TYPE_INT64: {
602                     add_camera_metadata_entry(aCamera->characteristics, tag, p, count);
603                     p += count * sizeof(int64_t);
604                     break;
605                 }
606                 case TYPE_DOUBLE: {
607                     add_camera_metadata_entry(aCamera->characteristics, tag, p, count);
608                     p += count * sizeof(double);
609                     break;
610                 }
611                 case TYPE_RATIONAL:
612                     p += count * sizeof(camera_metadata_rational_t);
613                     break;
614                 default:
615                     LOG(WARNING) << "Type " << type << " is unknown; "
616                                  << "data may be corrupted.";
617                     break;
618             }
619         }
620 
621         mCameraInfo.insert_or_assign(cameraId, std::move(aCamera));
622     }
623 
624     /* read number of camera information entries */
625     const size_t ncams = *(reinterpret_cast<size_t*>(p));
626     p += sizeof(size_t);
627 
628     /* read each camera information entry */
629     for (size_t cidx = 0; cidx < ncams; ++cidx) {
630         /* read camera identifier */
631         std::string cameraId = *(reinterpret_cast<std::string*>(p));
632         p += sizeof(std::string);
633 
634         /* size of camera_metadata_t */
635         const size_t num_entry = *(reinterpret_cast<size_t*>(p));
636         p += sizeof(size_t);
637         const size_t num_data = *(reinterpret_cast<size_t*>(p));
638         p += sizeof(size_t);
639 
640         /* create CameraInfo and add it to hash map */
641         std::unique_ptr<ConfigManager::CameraInfo> aCamera;
642         if (aCamera == nullptr || !aCamera->allocate(num_entry, num_data)) {
643             LOG(ERROR) << "Failed to create new CameraInfo object";
644             mCameraInfo.clear();
645             return false;
646         }
647 
648         /* controls */
649         typedef struct {
650             CameraParam cid;
651             int32_t min;
652             int32_t max;
653             int32_t step;
654         } CameraCtrl;
655         sz = *(reinterpret_cast<size_t*>(p));
656         p += sizeof(size_t);
657         CameraCtrl* ptr = reinterpret_cast<CameraCtrl*>(p);
658         for (size_t idx = 0; idx < sz; ++idx) {
659             CameraCtrl temp = *ptr++;
660             aCamera->controls.insert_or_assign(temp.cid,
661                                                std::move(std::make_tuple(temp.min, temp.max,
662                                                                          temp.step)));
663         }
664         p = reinterpret_cast<char*>(ptr);
665 
666         /* stream configurations */
667         sz = *(reinterpret_cast<size_t*>(p));
668         p += sizeof(size_t);
669         int32_t* i32_ptr = reinterpret_cast<int32_t*>(p);
670         for (size_t idx = 0; idx < sz; ++idx) {
671             const int32_t id = *i32_ptr++;
672 
673             StreamConfiguration temp;
674             memcpy(&temp, i32_ptr, sizeof(StreamConfiguration));
675             i32_ptr += sizeof(StreamConfiguration);
676             aCamera->streamConfigurations.insert_or_assign(id, temp);
677         }
678         p = reinterpret_cast<char*>(i32_ptr);
679 
680         for (size_t idx = 0; idx < num_entry; ++idx) {
681             /* Read camera metadata entries */
682             camera_metadata_tag_t tag = *reinterpret_cast<camera_metadata_tag_t*>(p);
683             p += sizeof(camera_metadata_tag_t);
684             const size_t count = *reinterpret_cast<size_t*>(p);
685             p += sizeof(size_t);
686 
687             const int32_t type = get_camera_metadata_tag_type(tag);
688             switch (type) {
689                 case TYPE_BYTE: {
690                     add_camera_metadata_entry(aCamera->characteristics, tag, p, count);
691                     p += count * sizeof(uint8_t);
692                     break;
693                 }
694                 case TYPE_INT32: {
695                     add_camera_metadata_entry(aCamera->characteristics, tag, p, count);
696                     p += count * sizeof(int32_t);
697                     break;
698                 }
699                 case TYPE_FLOAT: {
700                     add_camera_metadata_entry(aCamera->characteristics, tag, p, count);
701                     p += count * sizeof(float);
702                     break;
703                 }
704                 case TYPE_INT64: {
705                     add_camera_metadata_entry(aCamera->characteristics, tag, p, count);
706                     p += count * sizeof(int64_t);
707                     break;
708                 }
709                 case TYPE_DOUBLE: {
710                     add_camera_metadata_entry(aCamera->characteristics, tag, p, count);
711                     p += count * sizeof(double);
712                     break;
713                 }
714                 case TYPE_RATIONAL:
715                     p += count * sizeof(camera_metadata_rational_t);
716                     break;
717                 default:
718                     LOG(WARNING) << "Type " << type << " is unknown; "
719                                  << "data may be corrupted.";
720                     break;
721             }
722         }
723 
724         mCameraInfo.insert_or_assign(cameraId, std::move(aCamera));
725     }
726 
727     mIsReady = true;
728 
729     /* notify that configuration data is ready */
730     lock.unlock();
731     mConfigCond.notify_all();
732 
733     int64_t readEnd = android::elapsedRealtimeNano();
734     LOG(INFO) << __FUNCTION__ << " takes " << std::scientific
735               << (double)(readEnd - readStart) / 1000000.0 << " ms.";
736 
737     return true;
738 }
739 
writeConfigDataToBinary()740 bool ConfigManager::writeConfigDataToBinary() {
741     std::fstream outFile;
742 
743     const int64_t writeStart = android::elapsedRealtimeNano();
744 
745     outFile.open(mBinaryFilePath, std::fstream::out | std::fstream::binary);
746     if (!outFile) {
747         LOG(ERROR) << "Failed to open a destination binary file, " << mBinaryFilePath;
748         return false;
749     }
750 
751     /* lock a configuration data while it's being written to the filesystem */
752     std::lock_guard<std::mutex> lock(mConfigLock);
753 
754     /* write camera group information */
755     size_t sz = mCameraGroups.size();
756     outFile.write(reinterpret_cast<const char*>(&sz), sizeof(size_t));
757     for (auto&& [camId, camInfo] : mCameraGroups) {
758         LOG(INFO) << "Storing camera group " << camId;
759 
760         /* write a camera identifier string */
761         outFile.write(reinterpret_cast<const char*>(&camId), sizeof(std::string));
762 
763         /* controls */
764         sz = camInfo->controls.size();
765         outFile.write(reinterpret_cast<const char*>(&sz), sizeof(size_t));
766         for (auto&& [ctrl, range] : camInfo->controls) {
767             outFile.write(reinterpret_cast<const char*>(&ctrl), sizeof(CameraParam));
768             outFile.write(reinterpret_cast<const char*>(&std::get<0>(range)), sizeof(int32_t));
769             outFile.write(reinterpret_cast<const char*>(&std::get<1>(range)), sizeof(int32_t));
770             outFile.write(reinterpret_cast<const char*>(&std::get<2>(range)), sizeof(int32_t));
771         }
772 
773         /* stream configurations */
774         sz = camInfo->streamConfigurations.size();
775         outFile.write(reinterpret_cast<const char*>(&sz), sizeof(size_t));
776         for (auto&& [sid, cfg] : camInfo->streamConfigurations) {
777             outFile.write(reinterpret_cast<const char*>(sid), sizeof(int32_t));
778             outFile.write(reinterpret_cast<const char*>(&cfg), sizeof(cfg));
779         }
780 
781         /* synchronization */
782         outFile.write(reinterpret_cast<const char*>(&camInfo->synchronized), sizeof(int32_t));
783 
784         /* size of camera_metadata_t */
785         size_t num_entry = 0;
786         size_t num_data = 0;
787         if (camInfo->characteristics != nullptr) {
788             num_entry = get_camera_metadata_entry_count(camInfo->characteristics);
789             num_data = get_camera_metadata_data_count(camInfo->characteristics);
790         }
791         outFile.write(reinterpret_cast<const char*>(&num_entry), sizeof(size_t));
792         outFile.write(reinterpret_cast<const char*>(&num_data), sizeof(size_t));
793 
794         /* write each camera metadata entry */
795         if (num_entry > 0) {
796             camera_metadata_entry_t entry;
797             for (size_t idx = 0; idx < num_entry; ++idx) {
798                 if (get_camera_metadata_entry(camInfo->characteristics, idx, &entry)) {
799                     LOG(ERROR) << "Failed to retrieve camera metadata entry " << idx;
800                     outFile.close();
801                     return false;
802                 }
803 
804                 outFile.write(reinterpret_cast<const char*>(&entry.tag), sizeof(entry.tag));
805                 outFile.write(reinterpret_cast<const char*>(&entry.count), sizeof(entry.count));
806 
807                 int32_t type = get_camera_metadata_tag_type(entry.tag);
808                 switch (type) {
809                     case TYPE_BYTE:
810                         outFile.write(reinterpret_cast<const char*>(entry.data.u8),
811                                       sizeof(uint8_t) * entry.count);
812                         break;
813                     case TYPE_INT32:
814                         outFile.write(reinterpret_cast<const char*>(entry.data.i32),
815                                       sizeof(int32_t) * entry.count);
816                         break;
817                     case TYPE_FLOAT:
818                         outFile.write(reinterpret_cast<const char*>(entry.data.f),
819                                       sizeof(float) * entry.count);
820                         break;
821                     case TYPE_INT64:
822                         outFile.write(reinterpret_cast<const char*>(entry.data.i64),
823                                       sizeof(int64_t) * entry.count);
824                         break;
825                     case TYPE_DOUBLE:
826                         outFile.write(reinterpret_cast<const char*>(entry.data.d),
827                                       sizeof(double) * entry.count);
828                         break;
829                     case TYPE_RATIONAL:
830                         [[fallthrough]];
831                     default:
832                         LOG(WARNING) << "Type " << type << " is not supported.";
833                         break;
834                 }
835             }
836         }
837     }
838 
839     /* write camera device information */
840     sz = mCameraInfo.size();
841     outFile.write(reinterpret_cast<const char*>(&sz), sizeof(size_t));
842     for (auto&& [camId, camInfo] : mCameraInfo) {
843         LOG(INFO) << "Storing camera " << camId;
844 
845         /* write a camera identifier string */
846         outFile.write(reinterpret_cast<const char*>(&camId), sizeof(std::string));
847 
848         /* controls */
849         sz = camInfo->controls.size();
850         outFile.write(reinterpret_cast<const char*>(&sz), sizeof(size_t));
851         for (auto& [ctrl, range] : camInfo->controls) {
852             outFile.write(reinterpret_cast<const char*>(&ctrl), sizeof(CameraParam));
853             outFile.write(reinterpret_cast<const char*>(&std::get<0>(range)), sizeof(int32_t));
854             outFile.write(reinterpret_cast<const char*>(&std::get<1>(range)), sizeof(int32_t));
855             outFile.write(reinterpret_cast<const char*>(&std::get<2>(range)), sizeof(int32_t));
856         }
857 
858         /* stream configurations */
859         sz = camInfo->streamConfigurations.size();
860         outFile.write(reinterpret_cast<const char*>(&sz), sizeof(size_t));
861         for (auto&& [sid, cfg] : camInfo->streamConfigurations) {
862             outFile.write(reinterpret_cast<const char*>(sid), sizeof(int32_t));
863             outFile.write(reinterpret_cast<const char*>(&cfg), sizeof(cfg));
864         }
865 
866         /* size of camera_metadata_t */
867         size_t num_entry = 0;
868         size_t num_data = 0;
869         if (camInfo->characteristics != nullptr) {
870             num_entry = get_camera_metadata_entry_count(camInfo->characteristics);
871             num_data = get_camera_metadata_data_count(camInfo->characteristics);
872         }
873         outFile.write(reinterpret_cast<const char*>(&num_entry), sizeof(size_t));
874         outFile.write(reinterpret_cast<const char*>(&num_data), sizeof(size_t));
875 
876         /* write each camera metadata entry */
877         if (num_entry > 0) {
878             camera_metadata_entry_t entry;
879             for (size_t idx = 0; idx < num_entry; ++idx) {
880                 if (get_camera_metadata_entry(camInfo->characteristics, idx, &entry)) {
881                     LOG(ERROR) << "Failed to retrieve camera metadata entry " << idx;
882                     outFile.close();
883                     return false;
884                 }
885 
886                 outFile.write(reinterpret_cast<const char*>(&entry.tag), sizeof(entry.tag));
887                 outFile.write(reinterpret_cast<const char*>(&entry.count), sizeof(entry.count));
888 
889                 int32_t type = get_camera_metadata_tag_type(entry.tag);
890                 switch (type) {
891                     case TYPE_BYTE:
892                         outFile.write(reinterpret_cast<const char*>(entry.data.u8),
893                                       sizeof(uint8_t) * entry.count);
894                         break;
895                     case TYPE_INT32:
896                         outFile.write(reinterpret_cast<const char*>(entry.data.i32),
897                                       sizeof(int32_t) * entry.count);
898                         break;
899                     case TYPE_FLOAT:
900                         outFile.write(reinterpret_cast<const char*>(entry.data.f),
901                                       sizeof(float) * entry.count);
902                         break;
903                     case TYPE_INT64:
904                         outFile.write(reinterpret_cast<const char*>(entry.data.i64),
905                                       sizeof(int64_t) * entry.count);
906                         break;
907                     case TYPE_DOUBLE:
908                         outFile.write(reinterpret_cast<const char*>(entry.data.d),
909                                       sizeof(double) * entry.count);
910                         break;
911                     case TYPE_RATIONAL:
912                         [[fallthrough]];
913                     default:
914                         LOG(WARNING) << "Type " << type << " is not supported.";
915                         break;
916                 }
917             }
918         }
919     }
920 
921     outFile.close();
922     int64_t writeEnd = android::elapsedRealtimeNano();
923     LOG(INFO) << __FUNCTION__ << " takes " << std::scientific
924               << (double)(writeEnd - writeStart) / 1000000.0 << " ms.";
925 
926     return true;
927 }
928 
Create()929 std::unique_ptr<ConfigManager> ConfigManager::Create() {
930     std::unique_ptr<ConfigManager> cfgMgr(new ConfigManager());
931 
932     /*
933      * Read a configuration from XML file
934      *
935      * If this is too slow, ConfigManager::readConfigDataFromBinary() and
936      * ConfigManager::writeConfigDataToBinary()can serialize CameraInfo object
937      * to the filesystem and construct CameraInfo instead; this was
938      * evaluated as 10x faster.
939      */
940     if (!cfgMgr->readConfigDataFromXML()) {
941         return nullptr;
942     } else {
943         return cfgMgr;
944     }
945 }
946 
~CameraInfo()947 ConfigManager::CameraInfo::~CameraInfo() {
948     free_camera_metadata(characteristics);
949 
950     for (auto&& [tag, val] : cameraMetadata) {
951         switch (tag) {
952             case ANDROID_LENS_DISTORTION:
953             case ANDROID_LENS_POSE_ROTATION:
954             case ANDROID_LENS_POSE_TRANSLATION:
955             case ANDROID_LENS_INTRINSIC_CALIBRATION: {
956                 delete[] reinterpret_cast<float*>(val.first);
957                 break;
958             }
959 
960             case ANDROID_REQUEST_AVAILABLE_CAPABILITIES: {
961                 delete[] reinterpret_cast<
962                         camera_metadata_enum_android_request_available_capabilities_t*>(val.first);
963                 break;
964             }
965 
966             case ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS: {
967                 delete[] reinterpret_cast<char*>(val.first);
968                 break;
969             }
970 
971             default:
972                 LOG(WARNING) << "Tag " << std::hex << tag << " is not supported.  "
973                              << "Data may be corrupted?";
974                 break;
975         }
976     }
977 }
978