• 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 << "\"" << hostInfoMap_[name].hostId << "\", \"" << name << "\", \"" <<
113             hostInfoMap_[name].processPriority << "\", \"" << hostInfoMap_[name].threadPriority;
114         for (auto iter : hostInfoMap_[name].mallocOpt) {
115             ofs_ << "\", \"" << iter.first << "\", \"" << iter.second;
116         }
117         ofs_ << "\"],\n";
118     }
119 }
120 
EmitIdInfo(const std::string & name,std::set<std::string> & configedKeywords)121 void StartupCfgGen::EmitIdInfo(const std::string &name, std::set<std::string> &configedKeywords)
122 {
123    // If the parameter is configured in initconfig, uid and gid info is generated in function EmitInitConfigInfo.
124     if ((configedKeywords.find("uid") == configedKeywords.end())) {
125         ofs_ << UID_INFO << "\"" << hostInfoMap_[name].hostUID << "\",\n";
126     }
127 
128     if (configedKeywords.find("gid") == configedKeywords.end()) {
129         ofs_ << GID_INFO << hostInfoMap_[name].hostGID << "],\n";
130     }
131 }
132 
EmitHostCapsInfo(const std::string & name,std::set<std::string> & configedKeywords)133 void StartupCfgGen::EmitHostCapsInfo(const std::string &name, std::set<std::string> &configedKeywords)
134 {
135    // If the parameter is configured in initconfig, hostCaps info is generated in function EmitInitConfigInfo.
136     if (!hostInfoMap_[name].hostCaps.empty() && configedKeywords.find("caps") == configedKeywords.end()) {
137         ofs_ << CAPS_INFO << hostInfoMap_[name].hostCaps << "],\n";
138     }
139 }
140 
EmitHostCriticalInfo(const std::string & name,std::set<std::string> & configedKeywords)141 void StartupCfgGen::EmitHostCriticalInfo(const std::string &name, std::set<std::string> &configedKeywords)
142 {
143     // If the parameter is configured in initconfig, hostCritical info is generated in function EmitInitConfigInfo.
144     if (!hostInfoMap_[name].hostCritical.empty() && configedKeywords.find("critical") == configedKeywords.end()) {
145         ofs_ << CRITICAL_INFO << hostInfoMap_[name].hostCritical << "],\n";
146     }
147 }
148 
EmitSandBoxInfo(const std::string & name,std::set<std::string> & configedKeywords)149 void StartupCfgGen::EmitSandBoxInfo(const std::string &name, std::set<std::string> &configedKeywords)
150 {
151     // If the parameter is configured in initconfig, sandBox info is generated in function EmitInitConfigInfo.
152     if (hostInfoMap_[name].sandBox != INVALID_SAND_BOX && configedKeywords.find("sandbox") == configedKeywords.end()) {
153         ofs_ << SAND_BOX_INFO << hostInfoMap_[name].sandBox << ",\n";
154     }
155 }
156 
EmitSeconInfo(const std::string & name,std::set<std::string> & configedKeywords)157 void StartupCfgGen::EmitSeconInfo(const std::string &name, std::set<std::string> &configedKeywords)
158 {
159     // If the parameter is configured in initconfig, secon info is generated in function EmitInitConfigInfo.
160     if (configedKeywords.find("secon") == configedKeywords.end()) {
161         ofs_ << SECON_INFO << name << ":s0\"";
162         if (!hostInfoMap_[name].initConfig.empty()) {
163             ofs_ << ",";
164         }
165         ofs_ << "\n";
166     }
167 }
168 
EmitInitConfigInfo(const std::string & name)169 void StartupCfgGen::EmitInitConfigInfo(const std::string &name)
170 {
171     if (!hostInfoMap_[name].initConfig.empty()) {
172         for (auto &info : hostInfoMap_[name].initConfig) {
173             ofs_ << TAB TAB TAB << info;
174             if (&info != &hostInfoMap_[name].initConfig.back()) {
175                 ofs_ << ",";
176             }
177             ofs_ << "\n";
178         }
179     }
180 }
181 
HostInfoOutput(const std::string & name,bool end)182 void StartupCfgGen::HostInfoOutput(const std::string &name, bool end)
183 {
184     std::set<std::string> configedKeywords;
185     ofs_ << SERVICE_TOP << "\"" << name << "\",\n";
186 
187     if (!hostInfoMap_[name].initConfig.empty()) {
188         for (auto &info : hostInfoMap_[name].initConfig) {
189             int firstQuotePos = info.find("\"");
190             int secondQuotePos = info.find("\"", firstQuotePos + 1);
191             configedKeywords.insert(info.substr(firstQuotePos + 1, secondQuotePos - (firstQuotePos + 1)));
192         }
193     }
194 
195     EmitDynamicLoad(name, configedKeywords);
196     EmitPathInfo(name, configedKeywords);
197     EmitIdInfo(name, configedKeywords);
198     EmitHostCapsInfo(name, configedKeywords);
199     EmitHostCriticalInfo(name, configedKeywords);
200     EmitSandBoxInfo(name, configedKeywords);
201     EmitSeconInfo(name, configedKeywords);
202     EmitInitConfigInfo(name);
203 
204     ofs_ << TAB TAB << "}";
205     if (!end) {
206         ofs_<< ",";
207     }
208     ofs_ << '\n';
209 }
210 
InitHostInfo(HostInfo & hostData)211 void StartupCfgGen::InitHostInfo(HostInfo &hostData)
212 {
213     hostData.dynamicLoad = true;
214     hostData.hostCaps = "";
215     hostData.hostUID = "";
216     hostData.hostGID = "";
217     hostData.initConfig = {};
218     hostData.mallocOpt = {};
219     hostData.hostPriority = 0;
220     hostData.hostId = 0;
221     hostData.hostCritical = "";
222     hostData.processPriority = DEFAULT_PROCESS_PRIORITY; // -20(high) - 19(low), default 0
223     hostData.threadPriority = INVALID_PRIORITY; // 1(low) - 99(high)
224     hostData.sandBox = INVALID_SAND_BOX;
225 }
226 
TemplateNodeSeparate()227 bool StartupCfgGen::TemplateNodeSeparate()
228 {
229     return ast_->WalkBackward([this](std::shared_ptr<AstObject> &object, int32_t depth) {
230         (void)depth;
231         if (object->IsNode() && ConfigNode::CastFrom(object)->GetNodeType() == NODE_TEMPLATE) {
232             object->Separate();
233             return NOERR;
234         }
235         return NOERR;
236     });
237 }
238 
HostInfosOutput()239 void StartupCfgGen::HostInfosOutput()
240 {
241     bool end = false;
242     uint32_t cnt = 1;
243     const uint32_t size = hostInfoMap_.size();
244 
245     std::vector<std::pair<std::string, HostInfo>> vect(hostInfoMap_.begin(), hostInfoMap_.end());
246 
247     using ElementType = std::pair<std::string, HostInfo>;
248     sort(vect.begin(), vect.end(), [] (const ElementType &p1, const ElementType &p2) -> bool {
249         return (p1.second.hostPriority == p2.second.hostPriority) ?
250             (p1.second.hostId < p2.second.hostId) : (p1.second.hostPriority < p2.second.hostPriority);
251     });
252 
253     std::vector<std::pair<std::string, HostInfo>>::iterator it = vect.begin();
254     for (; it != vect.end(); ++it, ++cnt) {
255         if (cnt == size) {
256             end = true;
257         }
258         HostInfoOutput(it->first, end);
259     }
260 }
261 
GetConfigArray(const std::shared_ptr<AstObject> & term,std::string & config)262 void StartupCfgGen::GetConfigArray(const std::shared_ptr<AstObject> &term, std::string &config)
263 {
264     if (term == nullptr) {
265         Logger().Debug() << "GetConfigArray term is null" << '\n';
266         return;
267     }
268 
269     std::shared_ptr<AstObject> arrayObj = term->Child();
270     if (arrayObj == nullptr) {
271         Logger().Debug() << "GetConfigArray arrayObj is null" << '\n';
272         return;
273     }
274 
275     uint16_t arraySize = ConfigArray::CastFrom(arrayObj)->ArraySize();
276     std::shared_ptr<AstObject> object = arrayObj->Child();
277     while (arraySize && object != nullptr) {
278         if (!object->StringValue().empty()) {
279             config.append("\"").append(object->StringValue()).append("\"");
280             if (arraySize != 1) {
281                 config.append(", ");
282             }
283         }
284 
285         object = object->Next();
286         arraySize--;
287     }
288 }
289 
GetConfigIntArray(const std::shared_ptr<AstObject> & term,std::string & config)290 void StartupCfgGen::GetConfigIntArray(const std::shared_ptr<AstObject> &term, std::string &config)
291 {
292     if (term == nullptr) {
293         Logger().Debug() << "GetConfigIntArray term is null" << '\n';
294         return;
295     }
296 
297     std::shared_ptr<AstObject> intArrayObj = term->Child();
298     if (intArrayObj == nullptr) {
299         Logger().Debug() << "GetConfigIntArray intArrayObj is null" << '\n';
300         return;
301     }
302 
303     uint16_t arraySize = ConfigArray::CastFrom(intArrayObj)->ArraySize();
304     std::shared_ptr<AstObject> object = intArrayObj->Child();
305     while (arraySize && object != nullptr) {
306         std::string value = std::to_string(object->IntegerValue());
307         config.append(value);
308         if (arraySize != 1) {
309             config.append(", ");
310         }
311 
312         object = object->Next();
313         arraySize--;
314     }
315 }
316 
GetConfigVector(const std::shared_ptr<AstObject> & term,std::vector<std::string> & config)317 void StartupCfgGen::GetConfigVector(const std::shared_ptr<AstObject> &term, std::vector<std::string> &config)
318 {
319     if (term == nullptr) {
320         Logger().Debug() << "GetConfigVector term is null" << '\n';
321         return;
322     }
323 
324     std::shared_ptr<AstObject> arrayObj = term->Child();
325     if (arrayObj == nullptr) {
326         Logger().Debug() << "GetConfigVector arrayObj is null" << '\n';
327         return;
328     }
329 
330     std::shared_ptr<AstObject> object = arrayObj->Child();
331     while (object != nullptr) {
332         if (!object->StringValue().empty()) {
333             config.push_back(object->StringValue());
334         }
335 
336         object = object->Next();
337     }
338 }
339 
GetProcessPriority(const std::shared_ptr<AstObject> & term,HostInfo & hostData)340 void StartupCfgGen::GetProcessPriority(const std::shared_ptr<AstObject> &term, HostInfo &hostData)
341 {
342     if (term == nullptr) {
343         return;
344     }
345 
346     std::shared_ptr<AstObject> object = term->Lookup("processPriority", PARSEROP_CONFTERM);
347     if (object != nullptr) {
348         hostData.processPriority = static_cast<int32_t>(object->Child()->IntegerValue());
349     }
350     object = term->Lookup("threadPriority", PARSEROP_CONFTERM);
351     if (object != nullptr) {
352         hostData.threadPriority = static_cast<int32_t>(object->Child()->IntegerValue());
353     }
354 }
355 
GetMallocOpt(const std::shared_ptr<AstObject> & hostInfo,std::vector<std::pair<std::string,std::string>> & config)356 void StartupCfgGen::GetMallocOpt(const std::shared_ptr<AstObject> &hostInfo,
357     std::vector<std::pair<std::string, std::string>> &config)
358 {
359     std::shared_ptr<AstObject> term = hostInfo->Lookup("mallocopt", PARSEROP_CONFTERM);
360     std::vector<std::string> mallocOptions = {};
361     GetConfigVector(term, mallocOptions);
362     for (auto mallocOption : mallocOptions) {
363         int separatorPos = mallocOption.find(MALLOPT_SEPARATOR);
364         std::string malloptKey = mallocOption.substr(0, separatorPos);
365         std::string malloptValue = mallocOption.substr(separatorPos + 1,
366             mallocOption.length() - (separatorPos + 1));
367         config.push_back({malloptKey, malloptValue});
368     }
369 }
370 
GetHostLoadMode(const std::shared_ptr<AstObject> & hostInfo,HostInfo & hostData)371 void StartupCfgGen::GetHostLoadMode(const std::shared_ptr<AstObject> &hostInfo, HostInfo &hostData)
372 {
373     uint32_t preload;
374     std::shared_ptr<AstObject> current = nullptr;
375     std::shared_ptr<AstObject> devNodeInfo = nullptr;
376 
377     std::shared_ptr<AstObject> devInfo = hostInfo->Child();
378     while (devInfo != nullptr) {
379         if (!devInfo->IsNode()) {
380             devInfo = devInfo->Next();
381             continue;
382         }
383 
384         devNodeInfo = devInfo->Child();
385         while (devNodeInfo != nullptr) {
386             current = devNodeInfo->Lookup("preload", PARSEROP_CONFTERM);
387             if (current == nullptr) {
388                 devNodeInfo = devNodeInfo->Next();
389                 continue;
390             }
391 
392             preload = current->Child()->IntegerValue();
393             if (preload == 0 || preload == 1) {
394                 hostData.dynamicLoad = false;
395             }
396 
397             devNodeInfo = devNodeInfo->Next();
398         }
399         devInfo = devInfo->Next();
400     }
401 }
402 
GetHostGID(const std::shared_ptr<AstObject> & term,std::string & config,const std::string & name)403 void StartupCfgGen::GetHostGID(const std::shared_ptr<AstObject> &term, std::string &config,
404     const std::string &name)
405 {
406     // get array format configuration
407     GetConfigArray(term, config);
408 
409     // if the array format is not available, get the string format configuration
410     if (config.empty()) {
411         if (term != nullptr && !term->Child()->StringValue().empty()) {
412             config.append("\"").append(term->Child()->StringValue()).append("\"");
413         }
414     }
415 
416     // use the default name as gid
417     if (config.empty()) {
418         config.append("\"").append(name).append("\"");
419     }
420 }
421 
GetHostInfo()422 bool StartupCfgGen::GetHostInfo()
423 {
424     std::shared_ptr<AstObject> deviceInfo = ast_->GetAstRoot()->Lookup("device_info", PARSEROP_CONFNODE);
425     std::shared_ptr<AstObject> object = nullptr;
426     std::string serviceName;
427     HostInfo hostData;
428     uint32_t hostId = 0;
429 
430     if (deviceInfo == nullptr) {
431         Logger().Error() << "do not find device_info node";
432         return false;
433     }
434 
435     std::shared_ptr<AstObject> hostInfo = deviceInfo->Child();
436     while (hostInfo != nullptr) {
437         object = hostInfo->Lookup("hostName", PARSEROP_CONFTERM);
438         if (object == nullptr) {
439             hostInfo = hostInfo->Next();
440             continue;
441         }
442 
443         InitHostInfo(hostData);
444         serviceName = object->Child()->StringValue();
445 
446         object = hostInfo->Lookup("priority", PARSEROP_CONFTERM);
447         if (object != nullptr) {
448             hostData.hostPriority = object->Child()->IntegerValue();
449         }
450 
451         hostData.hostUID = serviceName;
452         object = hostInfo->Lookup("uid", PARSEROP_CONFTERM);
453         if (object != nullptr && !object->Child()->StringValue().empty()) {
454             hostData.hostUID = object->Child()->StringValue();
455         }
456 
457         object = hostInfo->Lookup("gid", PARSEROP_CONFTERM);
458         GetHostGID(object, hostData.hostGID, serviceName);
459 
460         object = hostInfo->Lookup("caps", PARSEROP_CONFTERM);
461         GetConfigArray(object, hostData.hostCaps);
462 
463         GetHostLoadMode(hostInfo, hostData);
464 
465         object = hostInfo->Lookup("critical", PARSEROP_CONFTERM);
466         GetConfigIntArray(object, hostData.hostCritical);
467         GetProcessPriority(hostInfo, hostData);
468 
469         object = hostInfo->Lookup("sandbox", PARSEROP_CONFTERM);
470         if (object != nullptr) {
471             hostData.sandBox = object->Child()->IntegerValue();
472         }
473 
474         object = hostInfo->Lookup("initconfig", PARSEROP_CONFTERM);
475         GetConfigVector(object, hostData.initConfig);
476 
477         GetMallocOpt(hostInfo, hostData.mallocOpt);
478 
479         hostData.hostId = hostId;
480         hostInfoMap_.insert(make_pair(serviceName, hostData));
481         hostId++;
482         hostInfo = hostInfo->Next();
483     }
484     return true;
485 }
486