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