1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 *
4 * HDF is dual licensed: you can use it either under the terms of
5 * the GPL, or the BSD license, at your option.
6 * See the LICENSE file in the root of this repository for complete details.
7 */
8
9 #include "startup_cfg_gen.h"
10 #include <algorithm>
11 #include <string>
12
13 #include "ast.h"
14 #include "file.h"
15 #include "logger.h"
16
17 using namespace OHOS::Hardware;
18
19 static constexpr const char *BOOT_CONFIG_TOP =
20 "{\n"
21 " \"jobs\" : [{\n"
22 " \"name\" : \"post-fs-data\",\n"
23 " \"cmds\" : [\n"
24 " ]\n"
25 " }\n"
26 " ],\n"
27 " \"services\" : [\n";
28 static constexpr const char *BOOT_CONFIG_BOTTOM =
29 " ]\n"
30 "}\n";
31 static constexpr const char *SERVICE_TOP =
32 " {\n"
33 " \"name\" : ";
34 static constexpr const char *PATH_INFO = " \"path\" : [\"/vendor/bin/hdf_devhost\", ";
35 static constexpr const char *UID_INFO = " \"uid\" : ";
36 static constexpr const char *GID_INFO = " \"gid\" : [";
37 static constexpr const char *CAPS_INFO = " \"caps\" : [";
38 static constexpr const char *DYNAMIC_INFO = " \"ondemand\" : true,\n";
39 static constexpr const char *SECON_INFO = " \"secon\" : \"u:r:";
40 static constexpr const char *CRITICAL_INFO = " \"critical\" : [";
41 static constexpr uint32_t DEFAULT_PROCESS_PRIORITY = 0;
42 static constexpr uint32_t INVALID_PRIORITY = 0;
43 static constexpr const char *SAND_BOX_INFO = " \"sandbox\" : ";
44 static constexpr uint32_t INVALID_SAND_BOX = 0xffffffff;
45 static constexpr const char *MALLOPT_SEPARATOR = ":";
StartupCfgGen(const std::shared_ptr<Ast> & ast)46 StartupCfgGen::StartupCfgGen(const std::shared_ptr<Ast> &ast) : Generator(ast)
47 {
48 }
49
HeaderTopOutput()50 void StartupCfgGen::HeaderTopOutput()
51 {
52 ofs_ << BOOT_CONFIG_TOP;
53 }
54
HeaderBottomOutput()55 void StartupCfgGen::HeaderBottomOutput()
56 {
57 ofs_ << BOOT_CONFIG_BOTTOM;
58 ofs_.close();
59 }
60
Output()61 bool StartupCfgGen::Output()
62 {
63 if (!Initialize()) {
64 return false;
65 }
66 if (!TemplateNodeSeparate()) {
67 return false;
68 }
69 HeaderTopOutput();
70
71 if (!GetHostInfo()) {
72 return false;
73 }
74 HostInfosOutput();
75
76 HeaderBottomOutput();
77
78 return true;
79 }
80
Initialize()81 bool StartupCfgGen::Initialize()
82 {
83 std::string outFileName = Option::Instance().GetOutputName();
84 if (outFileName.empty()) {
85 outFileName = Option::Instance().GetSourceNameBase();
86 }
87 outFileName = Util::File::StripSuffix(outFileName).append(".cfg");
88 outFileName_ = Util::File::FileNameBase(outFileName);
89
90 ofs_.open(outFileName, std::ofstream::out | std::ofstream::binary);
91 if (!ofs_.is_open()) {
92 Logger().Error() << "failed to open output file: " << outFileName;
93 return false;
94 }
95
96 Logger().Debug() << "output: " << outFileName << outFileName_ << '\n';
97
98 return true;
99 }
100
EmitDynamicLoad(const std::string & name,std::set<std::string> & configedKeywords)101 void StartupCfgGen::EmitDynamicLoad(const std::string &name, std::set<std::string> &configedKeywords)
102 {
103 // If the parameter is configured in initconfig, dynamicLoad info is generated in function EmitInitConfigInfo.
104 if (hostInfoMap_[name].dynamicLoad && (configedKeywords.find("preload") == configedKeywords.end())) {
105 ofs_ << DYNAMIC_INFO;
106 }
107 }
108
EmitPathInfo(const std::string & name,std::set<std::string> & configedKeywords)109 void StartupCfgGen::EmitPathInfo(const std::string &name, std::set<std::string> &configedKeywords)
110 {
111 if ((configedKeywords.find("path") == configedKeywords.end())) {
112 ofs_ << PATH_INFO << "\"" << "-i\", \"" << hostInfoMap_[name].hostId << "\", \"" << "-n\", \"" << name;
113 if (hostInfoMap_[name].processPriority != 0) {
114 ofs_ << "\", \"" << "-p\", \"" <<hostInfoMap_[name].processPriority;
115 }
116 if (hostInfoMap_[name].threadPriority != 0) {
117 ofs_ << "\", \"" << "-s\", \"" << hostInfoMap_[name].threadPriority;
118 }
119 for (auto iter : hostInfoMap_[name].mallocOpt) {
120 ofs_ << "\", \"" << iter.first << "\", \"" << iter.second;
121 }
122 ofs_ << "\"],\n";
123 }
124 }
125
EmitIdInfo(const std::string & name,std::set<std::string> & configedKeywords)126 void StartupCfgGen::EmitIdInfo(const std::string &name, std::set<std::string> &configedKeywords)
127 {
128 // If the parameter is configured in initconfig, uid and gid info is generated in function EmitInitConfigInfo.
129 if ((configedKeywords.find("uid") == configedKeywords.end())) {
130 ofs_ << UID_INFO << "\"" << hostInfoMap_[name].hostUID << "\",\n";
131 }
132
133 if (configedKeywords.find("gid") == configedKeywords.end()) {
134 ofs_ << GID_INFO << hostInfoMap_[name].hostGID << "],\n";
135 }
136 }
137
EmitHostCapsInfo(const std::string & name,std::set<std::string> & configedKeywords)138 void StartupCfgGen::EmitHostCapsInfo(const std::string &name, std::set<std::string> &configedKeywords)
139 {
140 // If the parameter is configured in initconfig, hostCaps info is generated in function EmitInitConfigInfo.
141 if (!hostInfoMap_[name].hostCaps.empty() && configedKeywords.find("caps") == configedKeywords.end()) {
142 ofs_ << CAPS_INFO << hostInfoMap_[name].hostCaps << "],\n";
143 }
144 }
145
EmitHostCriticalInfo(const std::string & name,std::set<std::string> & configedKeywords)146 void StartupCfgGen::EmitHostCriticalInfo(const std::string &name, std::set<std::string> &configedKeywords)
147 {
148 // If the parameter is configured in initconfig, hostCritical info is generated in function EmitInitConfigInfo.
149 if (!hostInfoMap_[name].hostCritical.empty() && configedKeywords.find("critical") == configedKeywords.end()) {
150 ofs_ << CRITICAL_INFO << hostInfoMap_[name].hostCritical << "],\n";
151 }
152 }
153
EmitSandBoxInfo(const std::string & name,std::set<std::string> & configedKeywords)154 void StartupCfgGen::EmitSandBoxInfo(const std::string &name, std::set<std::string> &configedKeywords)
155 {
156 // If the parameter is configured in initconfig, sandBox info is generated in function EmitInitConfigInfo.
157 if (hostInfoMap_[name].sandBox != INVALID_SAND_BOX && configedKeywords.find("sandbox") == configedKeywords.end()) {
158 ofs_ << SAND_BOX_INFO << hostInfoMap_[name].sandBox << ",\n";
159 }
160 }
161
EmitSeconInfo(const std::string & name,std::set<std::string> & configedKeywords)162 void StartupCfgGen::EmitSeconInfo(const std::string &name, std::set<std::string> &configedKeywords)
163 {
164 // If the parameter is configured in initconfig, secon info is generated in function EmitInitConfigInfo.
165 if (configedKeywords.find("secon") == configedKeywords.end()) {
166 ofs_ << SECON_INFO << name << ":s0\"";
167 if (!hostInfoMap_[name].initConfig.empty()) {
168 ofs_ << ",";
169 }
170 ofs_ << "\n";
171 }
172 }
173
EmitInitConfigInfo(const std::string & name)174 void StartupCfgGen::EmitInitConfigInfo(const std::string &name)
175 {
176 if (!hostInfoMap_[name].initConfig.empty()) {
177 for (auto &info : hostInfoMap_[name].initConfig) {
178 ofs_ << TAB TAB TAB << info;
179 if (&info != &hostInfoMap_[name].initConfig.back()) {
180 ofs_ << ",";
181 }
182 ofs_ << "\n";
183 }
184 }
185 }
186
HostInfoOutput(const std::string & name,bool end)187 void StartupCfgGen::HostInfoOutput(const std::string &name, bool end)
188 {
189 std::set<std::string> configedKeywords;
190 ofs_ << SERVICE_TOP << "\"" << name << "\",\n";
191
192 if (!hostInfoMap_[name].initConfig.empty()) {
193 for (auto &info : hostInfoMap_[name].initConfig) {
194 size_t firstQuotePos = info.find("\"");
195 size_t secondQuotePos = info.find("\"", firstQuotePos + 1);
196 configedKeywords.insert(info.substr(firstQuotePos + 1, secondQuotePos - (firstQuotePos + 1)));
197 }
198 }
199
200 EmitDynamicLoad(name, configedKeywords);
201 EmitPathInfo(name, configedKeywords);
202 EmitIdInfo(name, configedKeywords);
203 EmitHostCapsInfo(name, configedKeywords);
204 EmitHostCriticalInfo(name, configedKeywords);
205 EmitSandBoxInfo(name, configedKeywords);
206 EmitSeconInfo(name, configedKeywords);
207 EmitInitConfigInfo(name);
208
209 ofs_ << TAB TAB << "}";
210 if (!end) {
211 ofs_<< ",";
212 }
213 ofs_ << '\n';
214 }
215
InitHostInfo(HostInfo & hostData)216 void StartupCfgGen::InitHostInfo(HostInfo &hostData)
217 {
218 hostData.dynamicLoad = true;
219 hostData.hostCaps = "";
220 hostData.hostUID = "";
221 hostData.hostGID = "";
222 hostData.initConfig = {};
223 hostData.mallocOpt = {};
224 hostData.hostPriority = 0;
225 hostData.hostId = 0;
226 hostData.hostCritical = "";
227 hostData.processPriority = DEFAULT_PROCESS_PRIORITY; // -20(high) - 19(low), default 0
228 hostData.threadPriority = INVALID_PRIORITY; // 1(low) - 99(high)
229 hostData.sandBox = INVALID_SAND_BOX;
230 }
231
TemplateNodeSeparate()232 bool StartupCfgGen::TemplateNodeSeparate()
233 {
234 return ast_->WalkBackward([this](std::shared_ptr<AstObject> &object, int32_t depth) {
235 (void)depth;
236 if (object->IsNode() && ConfigNode::CastFrom(object)->GetNodeType() == NODE_TEMPLATE) {
237 object->Separate();
238 return NOERR;
239 }
240 return NOERR;
241 });
242 }
243
HostInfosOutput()244 void StartupCfgGen::HostInfosOutput()
245 {
246 bool end = false;
247 uint32_t cnt = 1;
248 const uint32_t size = hostInfoMap_.size();
249
250 std::vector<std::pair<std::string, HostInfo>> vect(hostInfoMap_.begin(), hostInfoMap_.end());
251
252 using ElementType = std::pair<std::string, HostInfo>;
253 sort(vect.begin(), vect.end(), [] (const ElementType &p1, const ElementType &p2) -> bool {
254 return (p1.second.hostPriority == p2.second.hostPriority) ?
255 (p1.second.hostId < p2.second.hostId) : (p1.second.hostPriority < p2.second.hostPriority);
256 });
257
258 std::vector<std::pair<std::string, HostInfo>>::iterator it = vect.begin();
259 for (; it != vect.end(); ++it, ++cnt) {
260 if (cnt == size) {
261 end = true;
262 }
263 HostInfoOutput(it->first, end);
264 }
265 }
266
GetConfigArray(const std::shared_ptr<AstObject> & term,std::string & config)267 void StartupCfgGen::GetConfigArray(const std::shared_ptr<AstObject> &term, std::string &config)
268 {
269 if (term == nullptr) {
270 Logger().Debug() << "GetConfigArray term is null" << '\n';
271 return;
272 }
273
274 std::shared_ptr<AstObject> arrayObj = term->Child();
275 if (arrayObj == nullptr) {
276 Logger().Debug() << "GetConfigArray arrayObj is null" << '\n';
277 return;
278 }
279
280 uint16_t arraySize = ConfigArray::CastFrom(arrayObj)->ArraySize();
281 std::shared_ptr<AstObject> object = arrayObj->Child();
282 while (arraySize && object != nullptr) {
283 if (!object->StringValue().empty()) {
284 config.append("\"").append(object->StringValue()).append("\"");
285 if (arraySize != 1) {
286 config.append(", ");
287 }
288 }
289
290 object = object->Next();
291 arraySize--;
292 }
293 }
294
GetConfigIntArray(const std::shared_ptr<AstObject> & term,std::string & config)295 void StartupCfgGen::GetConfigIntArray(const std::shared_ptr<AstObject> &term, std::string &config)
296 {
297 if (term == nullptr) {
298 Logger().Debug() << "GetConfigIntArray term is null" << '\n';
299 return;
300 }
301
302 std::shared_ptr<AstObject> intArrayObj = term->Child();
303 if (intArrayObj == nullptr) {
304 Logger().Debug() << "GetConfigIntArray intArrayObj is null" << '\n';
305 return;
306 }
307
308 uint16_t arraySize = ConfigArray::CastFrom(intArrayObj)->ArraySize();
309 std::shared_ptr<AstObject> object = intArrayObj->Child();
310 while (arraySize && object != nullptr) {
311 std::string value = std::to_string(object->IntegerValue());
312 config.append(value);
313 if (arraySize != 1) {
314 config.append(", ");
315 }
316
317 object = object->Next();
318 arraySize--;
319 }
320 }
321
GetConfigVector(const std::shared_ptr<AstObject> & term,std::vector<std::string> & config)322 void StartupCfgGen::GetConfigVector(const std::shared_ptr<AstObject> &term, std::vector<std::string> &config)
323 {
324 if (term == nullptr) {
325 Logger().Debug() << "GetConfigVector term is null" << '\n';
326 return;
327 }
328
329 std::shared_ptr<AstObject> arrayObj = term->Child();
330 if (arrayObj == nullptr) {
331 Logger().Debug() << "GetConfigVector arrayObj is null" << '\n';
332 return;
333 }
334
335 std::shared_ptr<AstObject> object = arrayObj->Child();
336 while (object != nullptr) {
337 if (!object->StringValue().empty()) {
338 config.push_back(object->StringValue());
339 }
340
341 object = object->Next();
342 }
343 }
344
GetProcessPriority(const std::shared_ptr<AstObject> & term,HostInfo & hostData)345 void StartupCfgGen::GetProcessPriority(const std::shared_ptr<AstObject> &term, HostInfo &hostData)
346 {
347 if (term == nullptr) {
348 return;
349 }
350
351 std::shared_ptr<AstObject> object = term->Lookup("processPriority", PARSEROP_CONFTERM);
352 if (object != nullptr) {
353 hostData.processPriority = static_cast<int32_t>(object->Child()->IntegerValue());
354 }
355 object = term->Lookup("threadPriority", PARSEROP_CONFTERM);
356 if (object != nullptr) {
357 hostData.threadPriority = static_cast<int32_t>(object->Child()->IntegerValue());
358 }
359 }
360
GetMallocOpt(const std::shared_ptr<AstObject> & hostInfo,std::vector<std::pair<std::string,std::string>> & config)361 void StartupCfgGen::GetMallocOpt(const std::shared_ptr<AstObject> &hostInfo,
362 std::vector<std::pair<std::string, std::string>> &config)
363 {
364 std::shared_ptr<AstObject> term = hostInfo->Lookup("mallocopt", PARSEROP_CONFTERM);
365 std::vector<std::string> mallocOptions = {};
366 GetConfigVector(term, mallocOptions);
367 for (auto mallocOption : mallocOptions) {
368 size_t separatorPos = mallocOption.find(MALLOPT_SEPARATOR);
369 std::string malloptKey = mallocOption.substr(0, separatorPos);
370 std::string malloptValue = mallocOption.substr(separatorPos + 1,
371 mallocOption.length() - (separatorPos + 1));
372 config.push_back({malloptKey, malloptValue});
373 }
374 }
375
GetHostLoadMode(const std::shared_ptr<AstObject> & hostInfo,HostInfo & hostData)376 void StartupCfgGen::GetHostLoadMode(const std::shared_ptr<AstObject> &hostInfo, HostInfo &hostData)
377 {
378 uint32_t preload;
379 std::shared_ptr<AstObject> current = nullptr;
380 std::shared_ptr<AstObject> devNodeInfo = nullptr;
381
382 std::shared_ptr<AstObject> devInfo = hostInfo->Child();
383 while (devInfo != nullptr) {
384 if (!devInfo->IsNode()) {
385 devInfo = devInfo->Next();
386 continue;
387 }
388
389 devNodeInfo = devInfo->Child();
390 while (devNodeInfo != nullptr) {
391 current = devNodeInfo->Lookup("preload", PARSEROP_CONFTERM);
392 if (current == nullptr) {
393 devNodeInfo = devNodeInfo->Next();
394 continue;
395 }
396
397 preload = current->Child()->IntegerValue();
398 if (preload == 0 || preload == 1) {
399 hostData.dynamicLoad = false;
400 }
401
402 devNodeInfo = devNodeInfo->Next();
403 }
404 devInfo = devInfo->Next();
405 }
406 }
407
GetHostGID(const std::shared_ptr<AstObject> & term,std::string & config,const std::string & name)408 void StartupCfgGen::GetHostGID(const std::shared_ptr<AstObject> &term, std::string &config,
409 const std::string &name)
410 {
411 // get array format configuration
412 GetConfigArray(term, config);
413
414 // if the array format is not available, get the string format configuration
415 if (config.empty()) {
416 if (term != nullptr && !term->Child()->StringValue().empty()) {
417 config.append("\"").append(term->Child()->StringValue()).append("\"");
418 }
419 }
420
421 // use the default name as gid
422 if (config.empty()) {
423 config.append("\"").append(name).append("\"");
424 }
425 }
426
GetHostInfo()427 bool StartupCfgGen::GetHostInfo()
428 {
429 std::shared_ptr<AstObject> deviceInfo = ast_->GetAstRoot()->Lookup("device_info", PARSEROP_CONFNODE);
430 std::shared_ptr<AstObject> object = nullptr;
431 std::string serviceName;
432 HostInfo hostData;
433 uint32_t hostId = 0;
434
435 if (deviceInfo == nullptr) {
436 Logger().Error() << "do not find device_info node";
437 return false;
438 }
439
440 std::shared_ptr<AstObject> hostInfo = deviceInfo->Child();
441 while (hostInfo != nullptr) {
442 object = hostInfo->Lookup("hostName", PARSEROP_CONFTERM);
443 if (object == nullptr) {
444 hostInfo = hostInfo->Next();
445 continue;
446 }
447
448 InitHostInfo(hostData);
449 serviceName = object->Child()->StringValue();
450
451 object = hostInfo->Lookup("priority", PARSEROP_CONFTERM);
452 if (object != nullptr) {
453 hostData.hostPriority = object->Child()->IntegerValue();
454 }
455
456 hostData.hostUID = serviceName;
457 object = hostInfo->Lookup("uid", PARSEROP_CONFTERM);
458 if (object != nullptr && !object->Child()->StringValue().empty()) {
459 hostData.hostUID = object->Child()->StringValue();
460 }
461
462 object = hostInfo->Lookup("gid", PARSEROP_CONFTERM);
463 GetHostGID(object, hostData.hostGID, serviceName);
464
465 object = hostInfo->Lookup("caps", PARSEROP_CONFTERM);
466 GetConfigArray(object, hostData.hostCaps);
467
468 GetHostLoadMode(hostInfo, hostData);
469
470 object = hostInfo->Lookup("critical", PARSEROP_CONFTERM);
471 GetConfigIntArray(object, hostData.hostCritical);
472 GetProcessPriority(hostInfo, hostData);
473
474 object = hostInfo->Lookup("sandbox", PARSEROP_CONFTERM);
475 if (object != nullptr) {
476 hostData.sandBox = object->Child()->IntegerValue();
477 }
478
479 object = hostInfo->Lookup("initconfig", PARSEROP_CONFTERM);
480 GetConfigVector(object, hostData.initConfig);
481
482 GetMallocOpt(hostInfo, hostData.mallocOpt);
483
484 hostData.hostId = hostId;
485 hostInfoMap_.insert(make_pair(serviceName, hostData));
486 hostId++;
487 hostInfo = hostInfo->Next();
488 }
489 return true;
490 }
491