xref: /aosp_15_r20/hardware/interfaces/automotive/evs/1.1/default/ConfigManager.cpp (revision 4d7e907c777eeecc4c5bd7cf640a754fac206ff7)
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 #include "ConfigManager.h"
18 
19 #include <android/hardware/camera/device/3.2/ICameraDevice.h>
20 #include <hardware/gralloc.h>
21 #include <utils/SystemClock.h>
22 
23 #include <fstream>
24 #include <sstream>
25 #include <thread>
26 
27 namespace android::hardware::automotive::evs::V1_1::implementation {
28 
29 using namespace std;
30 using namespace tinyxml2;
31 using hardware::camera::device::V3_2::StreamRotation;
32 
~ConfigManager()33 ConfigManager::~ConfigManager() {
34     /* Nothing to do */
35 }
36 
readCameraInfo(const XMLElement * const aCameraElem)37 void ConfigManager::readCameraInfo(const XMLElement* const aCameraElem) {
38     if (aCameraElem == nullptr) {
39         ALOGW("XML file does not have required camera element");
40         return;
41     }
42 
43     const XMLElement* curElem = aCameraElem->FirstChildElement();
44     while (curElem != nullptr) {
45         if (!strcmp(curElem->Name(), "group")) {
46             /* camera group identifier */
47             const char* id = curElem->FindAttribute("id")->Value();
48 
49             /* create a camera group to be filled */
50             CameraGroupInfo* aCamera = new CameraGroupInfo();
51 
52             /* read camera device information */
53             if (!readCameraDeviceInfo(aCamera, curElem)) {
54                 ALOGW("Failed to read a camera information of %s", id);
55                 delete aCamera;
56                 continue;
57             }
58 
59             /* camera group synchronization */
60             const char* sync = curElem->FindAttribute("synchronized")->Value();
61             if (!strcmp(sync, "CALIBRATED")) {
62                 aCamera->synchronized = ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_CALIBRATED;
63             } else if (!strcmp(sync, "APPROXIMATE")) {
64                 aCamera->synchronized = ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_APPROXIMATE;
65             } else {
66                 aCamera->synchronized = 0;  // Not synchronized
67             }
68 
69             /* add a group to hash map */
70             mCameraGroupInfos.insert_or_assign(id, unique_ptr<CameraGroupInfo>(aCamera));
71         } else if (!strcmp(curElem->Name(), "device")) {
72             /* camera unique identifier */
73             const char* id = curElem->FindAttribute("id")->Value();
74 
75             /* camera mount location */
76             const char* pos = curElem->FindAttribute("position")->Value();
77 
78             /* create a camera device to be filled */
79             CameraInfo* aCamera = new CameraInfo();
80 
81             /* read camera device information */
82             if (!readCameraDeviceInfo(aCamera, curElem)) {
83                 ALOGW("Failed to read a camera information of %s", id);
84                 delete aCamera;
85                 continue;
86             }
87 
88             /* store read camera module information */
89             mCameraInfo.insert_or_assign(id, unique_ptr<CameraInfo>(aCamera));
90 
91             /* assign a camera device to a position group */
92             mCameraPosition[pos].emplace(id);
93         } else {
94             /* ignore other device types */
95             ALOGD("Unknown element %s is ignored", curElem->Name());
96         }
97 
98         curElem = curElem->NextSiblingElement();
99     }
100 }
101 
readCameraDeviceInfo(CameraInfo * aCamera,const XMLElement * aDeviceElem)102 bool ConfigManager::readCameraDeviceInfo(CameraInfo* aCamera, const XMLElement* aDeviceElem) {
103     if (aCamera == nullptr || aDeviceElem == nullptr) {
104         return false;
105     }
106 
107     /* size information to allocate camera_metadata_t */
108     size_t totalEntries = 0;
109     size_t totalDataSize = 0;
110 
111     /* read device capabilities */
112     totalEntries +=
113             readCameraCapabilities(aDeviceElem->FirstChildElement("caps"), aCamera, totalDataSize);
114 
115     /* read camera metadata */
116     totalEntries += readCameraMetadata(aDeviceElem->FirstChildElement("characteristics"), aCamera,
117                                        totalDataSize);
118 
119     /* construct camera_metadata_t */
120     if (!constructCameraMetadata(aCamera, totalEntries, totalDataSize)) {
121         ALOGW("Either failed to allocate memory or "
122               "allocated memory was not large enough");
123     }
124 
125     return true;
126 }
127 
readCameraCapabilities(const XMLElement * const aCapElem,CameraInfo * aCamera,size_t & dataSize)128 size_t ConfigManager::readCameraCapabilities(const XMLElement* const aCapElem, CameraInfo* aCamera,
129                                              size_t& dataSize) {
130     if (aCapElem == nullptr || aCamera == nullptr) {
131         return 0;
132     }
133 
134     string token;
135     const XMLElement* curElem = nullptr;
136 
137     /* a list of supported camera parameters/controls */
138     curElem = aCapElem->FirstChildElement("supported_controls");
139     if (curElem != nullptr) {
140         const XMLElement* ctrlElem = curElem->FirstChildElement("control");
141         while (ctrlElem != nullptr) {
142             const char* nameAttr = ctrlElem->FindAttribute("name")->Value();
143             ;
144             const int32_t minVal = stoi(ctrlElem->FindAttribute("min")->Value());
145             const int32_t maxVal = stoi(ctrlElem->FindAttribute("max")->Value());
146 
147             int32_t stepVal = 1;
148             const XMLAttribute* stepAttr = ctrlElem->FindAttribute("step");
149             if (stepAttr != nullptr) {
150                 stepVal = stoi(stepAttr->Value());
151             }
152 
153             CameraParam aParam;
154             if (ConfigManagerUtil::convertToEvsCameraParam(nameAttr, aParam)) {
155                 aCamera->controls.emplace(aParam, make_tuple(minVal, maxVal, stepVal));
156             }
157 
158             ctrlElem = ctrlElem->NextSiblingElement("control");
159         }
160     }
161 
162     /* a list of camera stream configurations */
163     curElem = aCapElem->FirstChildElement("stream");
164     while (curElem != nullptr) {
165         /* read 5 attributes */
166         const XMLAttribute* idAttr = curElem->FindAttribute("id");
167         const XMLAttribute* widthAttr = curElem->FindAttribute("width");
168         const XMLAttribute* heightAttr = curElem->FindAttribute("height");
169         const XMLAttribute* fmtAttr = curElem->FindAttribute("format");
170         const XMLAttribute* fpsAttr = curElem->FindAttribute("framerate");
171 
172         const int32_t id = stoi(idAttr->Value());
173         int32_t framerate = 0;
174         if (fpsAttr != nullptr) {
175             framerate = stoi(fpsAttr->Value());
176         }
177 
178         int32_t pixFormat;
179         if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(), pixFormat)) {
180             RawStreamConfiguration cfg = {id,
181                                           stoi(widthAttr->Value()),
182                                           stoi(heightAttr->Value()),
183                                           pixFormat,
184                                           ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
185                                           framerate};
186             aCamera->streamConfigurations.insert_or_assign(id, cfg);
187         }
188 
189         curElem = curElem->NextSiblingElement("stream");
190     }
191 
192     dataSize = calculate_camera_metadata_entry_data_size(
193             get_camera_metadata_tag_type(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS),
194             aCamera->streamConfigurations.size() * kStreamCfgSz);
195 
196     /* a single camera metadata entry contains multiple stream configurations */
197     return dataSize > 0 ? 1 : 0;
198 }
199 
readCameraMetadata(const XMLElement * const aParamElem,CameraInfo * aCamera,size_t & dataSize)200 size_t ConfigManager::readCameraMetadata(const XMLElement* const aParamElem, CameraInfo* aCamera,
201                                          size_t& dataSize) {
202     if (aParamElem == nullptr || aCamera == nullptr) {
203         return 0;
204     }
205 
206     const XMLElement* curElem = aParamElem->FirstChildElement("parameter");
207     size_t numEntries = 0;
208     camera_metadata_tag_t tag;
209     while (curElem != nullptr) {
210         if (!ConfigManagerUtil::convertToMetadataTag(curElem->FindAttribute("name")->Value(),
211                                                      tag)) {
212             switch (tag) {
213                 case ANDROID_LENS_DISTORTION:
214                 case ANDROID_LENS_POSE_ROTATION:
215                 case ANDROID_LENS_POSE_TRANSLATION:
216                 case ANDROID_LENS_INTRINSIC_CALIBRATION: {
217                     /* float[] */
218                     size_t count = 0;
219                     void* data = ConfigManagerUtil::convertFloatArray(
220                             curElem->FindAttribute("size")->Value(),
221                             curElem->FindAttribute("value")->Value(), count);
222 
223                     aCamera->cameraMetadata.insert_or_assign(
224                             tag, make_pair(make_unique<void*>(data), count));
225 
226                     ++numEntries;
227                     dataSize += calculate_camera_metadata_entry_data_size(
228                             get_camera_metadata_tag_type(tag), count);
229 
230                     break;
231                 }
232 
233                 case ANDROID_REQUEST_AVAILABLE_CAPABILITIES: {
234                     camera_metadata_enum_android_request_available_capabilities_t* data =
235                             new camera_metadata_enum_android_request_available_capabilities_t[1];
236                     if (ConfigManagerUtil::convertToCameraCapability(
237                                 curElem->FindAttribute("value")->Value(), *data)) {
238                         curElem->FindAttribute("value")->Value(),
239                                 aCamera->cameraMetadata.insert_or_assign(
240                                         tag, make_pair(make_unique<void*>(data), 1));
241 
242                         ++numEntries;
243                         dataSize += calculate_camera_metadata_entry_data_size(
244                                 get_camera_metadata_tag_type(tag), 1);
245                     }
246                     break;
247                 }
248 
249                 case ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS: {
250                     /* a comma-separated list of physical camera devices */
251                     size_t len = strlen(curElem->FindAttribute("value")->Value());
252                     char* data = new char[len + 1];
253                     memcpy(data, curElem->FindAttribute("value")->Value(), len * sizeof(char));
254 
255                     /* replace commas with null char */
256                     char* p = data;
257                     while (*p != '\0') {
258                         if (*p == ',') {
259                             *p = '\0';
260                         }
261                         ++p;
262                     }
263 
264                     aCamera->cameraMetadata.insert_or_assign(
265                             tag, make_pair(make_unique<void*>(data), len));
266 
267                     ++numEntries;
268                     dataSize += calculate_camera_metadata_entry_data_size(
269                             get_camera_metadata_tag_type(tag), len);
270                     break;
271                 }
272 
273                 default:
274                     ALOGW("Parameter %s is not supported", curElem->FindAttribute("name")->Value());
275                     break;
276             }
277         }
278 
279         curElem = curElem->NextSiblingElement("parameter");
280     }
281 
282     return numEntries;
283 }
284 
constructCameraMetadata(CameraInfo * aCamera,const size_t totalEntries,const size_t totalDataSize)285 bool ConfigManager::constructCameraMetadata(CameraInfo* aCamera, const size_t totalEntries,
286                                             const size_t totalDataSize) {
287     if (aCamera == nullptr || !aCamera->allocate(totalEntries, totalDataSize)) {
288         ALOGE("Failed to allocate memory for camera metadata");
289         return false;
290     }
291 
292     const size_t numStreamConfigs = aCamera->streamConfigurations.size();
293     unique_ptr<int32_t[]> data(new int32_t[kStreamCfgSz * numStreamConfigs]);
294     int32_t* ptr = data.get();
295     for (auto& cfg : aCamera->streamConfigurations) {
296         for (auto i = 0; i < kStreamCfgSz; ++i) {
297             *ptr++ = cfg.second[i];
298         }
299     }
300     int32_t err = add_camera_metadata_entry(aCamera->characteristics,
301                                             ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
302                                             data.get(), numStreamConfigs * kStreamCfgSz);
303 
304     if (err) {
305         ALOGE("Failed to add stream configurations to metadata, ignored");
306         return false;
307     }
308 
309     bool success = true;
310     for (auto& [tag, entry] : aCamera->cameraMetadata) {
311         /* try to add new camera metadata entry */
312         int32_t err = add_camera_metadata_entry(aCamera->characteristics, tag, entry.first.get(),
313                                                 entry.second);
314         if (err) {
315             ALOGE("Failed to add an entry with a tag 0x%X", tag);
316 
317             /* may exceed preallocated capacity */
318             ALOGE("Camera metadata has %ld / %ld entries and %ld / %ld bytes are filled",
319                   (long)get_camera_metadata_entry_count(aCamera->characteristics),
320                   (long)get_camera_metadata_entry_capacity(aCamera->characteristics),
321                   (long)get_camera_metadata_data_count(aCamera->characteristics),
322                   (long)get_camera_metadata_data_capacity(aCamera->characteristics));
323             ALOGE("\tCurrent metadata entry requires %ld bytes",
324                   (long)calculate_camera_metadata_entry_data_size(tag, entry.second));
325 
326             success = false;
327         }
328     }
329 
330     ALOGV("Camera metadata has %ld / %ld entries and %ld / %ld bytes are filled",
331           (long)get_camera_metadata_entry_count(aCamera->characteristics),
332           (long)get_camera_metadata_entry_capacity(aCamera->characteristics),
333           (long)get_camera_metadata_data_count(aCamera->characteristics),
334           (long)get_camera_metadata_data_capacity(aCamera->characteristics));
335 
336     return success;
337 }
338 
readSystemInfo(const XMLElement * const aSysElem)339 void ConfigManager::readSystemInfo(const XMLElement* const aSysElem) {
340     if (aSysElem == nullptr) {
341         return;
342     }
343 
344     /*
345      * Please note that this function assumes that a given system XML element
346      * and its child elements follow DTD.  If it does not, it will cause a
347      * segmentation fault due to the failure of finding expected attributes.
348      */
349 
350     /* read number of cameras available in the system */
351     const XMLElement* xmlElem = aSysElem->FirstChildElement("num_cameras");
352     if (xmlElem != nullptr) {
353         mSystemInfo.numCameras = stoi(xmlElem->FindAttribute("value")->Value());
354     }
355 }
356 
readDisplayInfo(const XMLElement * const aDisplayElem)357 void ConfigManager::readDisplayInfo(const XMLElement* const aDisplayElem) {
358     if (aDisplayElem == nullptr) {
359         ALOGW("XML file does not have required camera element");
360         return;
361     }
362 
363     const XMLElement* curDev = aDisplayElem->FirstChildElement("device");
364     while (curDev != nullptr) {
365         const char* id = curDev->FindAttribute("id")->Value();
366         // const char *pos = curDev->FirstAttribute("position")->Value();
367 
368         unique_ptr<DisplayInfo> dpy(new DisplayInfo());
369         if (dpy == nullptr) {
370             ALOGE("Failed to allocate memory for DisplayInfo");
371             return;
372         }
373 
374         const XMLElement* cap = curDev->FirstChildElement("caps");
375         if (cap != nullptr) {
376             const XMLElement* curStream = cap->FirstChildElement("stream");
377             while (curStream != nullptr) {
378                 /* read 4 attributes */
379                 const XMLAttribute* idAttr = curStream->FindAttribute("id");
380                 const XMLAttribute* widthAttr = curStream->FindAttribute("width");
381                 const XMLAttribute* heightAttr = curStream->FindAttribute("height");
382                 const XMLAttribute* fmtAttr = curStream->FindAttribute("format");
383 
384                 const int32_t id = stoi(idAttr->Value());
385                 int32_t pixFormat;
386                 if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(), pixFormat)) {
387                     RawStreamConfiguration cfg = {
388                             id,
389                             stoi(widthAttr->Value()),
390                             stoi(heightAttr->Value()),
391                             pixFormat,
392                             ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT,
393                             0  // unused
394                     };
395                     dpy->streamConfigurations.insert_or_assign(id, cfg);
396                 }
397 
398                 curStream = curStream->NextSiblingElement("stream");
399             }
400         }
401 
402         mDisplayInfo.insert_or_assign(id, std::move(dpy));
403         curDev = curDev->NextSiblingElement("device");
404     }
405 
406     return;
407 }
408 
readConfigDataFromXML()409 bool ConfigManager::readConfigDataFromXML() noexcept {
410     XMLDocument xmlDoc;
411 
412     const int64_t parsingStart = android::elapsedRealtimeNano();
413 
414     /* load and parse a configuration file */
415     xmlDoc.LoadFile(mConfigFilePath);
416     if (xmlDoc.ErrorID() != XML_SUCCESS) {
417         ALOGE("Failed to load and/or parse a configuration file, %s", xmlDoc.ErrorStr());
418         return false;
419     }
420 
421     /* retrieve the root element */
422     const XMLElement* rootElem = xmlDoc.RootElement();
423     if (strcmp(rootElem->Name(), "configuration")) {
424         ALOGE("A configuration file is not in the required format.  "
425               "See /etc/automotive/evs/evs_configuration.dtd");
426         return false;
427     }
428 
429     /*
430      * parse camera information; this needs to be done before reading system
431      * information
432      */
433     readCameraInfo(rootElem->FirstChildElement("camera"));
434 
435     /* parse system information */
436     readSystemInfo(rootElem->FirstChildElement("system"));
437 
438     /* parse display information */
439     readDisplayInfo(rootElem->FirstChildElement("display"));
440 
441     const int64_t parsingEnd = android::elapsedRealtimeNano();
442     ALOGI("Parsing configuration file takes %lf (ms)",
443           (double)(parsingEnd - parsingStart) / 1000000.0);
444 
445     return true;
446 }
447 
Create(const char * path)448 std::unique_ptr<ConfigManager> ConfigManager::Create(const char* path) {
449     unique_ptr<ConfigManager> cfgMgr(new ConfigManager(path));
450 
451     /*
452      * Read a configuration from XML file
453      *
454      * If this is too slow, ConfigManager::readConfigDataFromBinary() and
455      * ConfigManager::writeConfigDataToBinary()can serialize CameraInfo object
456      * to the filesystem and construct CameraInfo instead; this was
457      * evaluated as 10x faster.
458      */
459     if (!cfgMgr->readConfigDataFromXML()) {
460         return nullptr;
461     } else {
462         return cfgMgr;
463     }
464 }
465 
466 }  // namespace android::hardware::automotive::evs::V1_1::implementation
467