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