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