• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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