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 #include "ast.h"
13 #include "file.h"
14 #include "logger.h"
15
16 using namespace OHOS::Hardware;
17
18 static constexpr const char *BOOT_CONFIG_TOP =
19 "{\n"
20 " \"jobs\" : [{\n"
21 " \"name\" : \"post-fs-data\",\n"
22 " \"cmds\" : [\n"
23 " \"start hdf_devhost\"\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 INVALID_PRIORITY = 0xffffffff;
42 static constexpr const char *SAND_BOX_INFO = " \"sandbox\" : ";
43 static constexpr uint32_t INVALID_SAND_BOX = 0xffffffff;
StartupCfgGen(const std::shared_ptr<Ast> & ast)44 StartupCfgGen::StartupCfgGen(const std::shared_ptr<Ast> &ast) : Generator(ast)
45 {
46 }
47
HeaderTopOutput()48 void StartupCfgGen::HeaderTopOutput()
49 {
50 ofs_ << BOOT_CONFIG_TOP;
51 }
52
HeaderBottomOutput()53 void StartupCfgGen::HeaderBottomOutput()
54 {
55 ofs_ << BOOT_CONFIG_BOTTOM;
56 ofs_.close();
57 }
58
Output()59 bool StartupCfgGen::Output()
60 {
61 if (!Initialize()) {
62 return false;
63 }
64 if (!TemplateNodeSeparate()) {
65 return false;
66 }
67 HeaderTopOutput();
68
69 if (!GetHostInfo()) {
70 return false;
71 }
72 HostInfosOutput();
73
74 HeaderBottomOutput();
75
76 return true;
77 }
78
Initialize()79 bool StartupCfgGen::Initialize()
80 {
81 std::string outFileName = Option::Instance().GetOutputName();
82 if (outFileName.empty()) {
83 outFileName = Option::Instance().GetSourceNameBase();
84 }
85 outFileName = Util::File::StripSuffix(outFileName).append(".cfg");
86 outFileName_ = Util::File::FileNameBase(outFileName);
87
88 ofs_.open(outFileName, std::ofstream::out | std::ofstream::binary);
89 if (!ofs_.is_open()) {
90 Logger().Error() << "failed to open output file: " << outFileName;
91 return false;
92 }
93
94 Logger().Debug() << "output: " << outFileName << outFileName_ << '\n';
95
96 return true;
97 }
98
HostInfoOutput(const std::string & name,bool end)99 void StartupCfgGen::HostInfoOutput(const std::string &name, bool end)
100 {
101 ofs_ << SERVICE_TOP << "\"" << name << "\",\n";
102
103 if (hostInfoMap_[name].dynamicLoad) {
104 ofs_ << DYNAMIC_INFO;
105 }
106
107 bool flag = false;
108 if ((hostInfoMap_[name].processPriority != INVALID_PRIORITY) &&
109 (hostInfoMap_[name].threadPriority != INVALID_PRIORITY)) {
110 flag = true;
111 }
112 if (flag) {
113 ofs_ << PATH_INFO << "\"" << hostInfoMap_[name].hostId << "\", \"" << name << "\", \"" <<
114 hostInfoMap_[name].processPriority << "\", \"" << hostInfoMap_[name].threadPriority << "\"],\n";
115 } else {
116 ofs_ << PATH_INFO << "\"" << hostInfoMap_[name].hostId << "\", \"" << name << "\"],\n";
117 }
118
119 ofs_ << UID_INFO << "\"" << hostInfoMap_[name].hostUID << "\",\n";
120 ofs_ << GID_INFO << hostInfoMap_[name].hostGID << "],\n";
121
122 if (!hostInfoMap_[name].hostCaps.empty()) {
123 ofs_ << CAPS_INFO << hostInfoMap_[name].hostCaps << "],\n";
124 }
125
126 if (!hostInfoMap_[name].hostCritical.empty()) {
127 ofs_ << CRITICAL_INFO << hostInfoMap_[name].hostCritical << "],\n";
128 }
129
130 if (hostInfoMap_[name].sandBox != INVALID_SAND_BOX) {
131 ofs_ << SAND_BOX_INFO << hostInfoMap_[name].sandBox << ",\n";
132 }
133
134 ofs_ << SECON_INFO << name << ":s0\"\n";
135
136 ofs_ << TAB TAB << "}";
137
138 if (!end) {
139 ofs_<< ",";
140 }
141 ofs_ << '\n';
142 }
143
InitHostInfo(HostInfo & hostData)144 void StartupCfgGen::InitHostInfo(HostInfo &hostData)
145 {
146 hostData.dynamicLoad = true;
147 hostData.hostCaps = "";
148 hostData.hostUID = "";
149 hostData.hostGID = "";
150 hostData.hostPriority = 0;
151 hostData.hostId = 0;
152 hostData.hostCritical = "";
153 hostData.processPriority = INVALID_PRIORITY;
154 hostData.threadPriority = INVALID_PRIORITY;
155 hostData.sandBox = INVALID_SAND_BOX;
156 }
157
TemplateNodeSeparate()158 bool StartupCfgGen::TemplateNodeSeparate()
159 {
160 return ast_->WalkBackward([this](std::shared_ptr<AstObject> &object, int32_t depth) {
161 (void)depth;
162 if (object->IsNode() && ConfigNode::CastFrom(object)->GetNodeType() == NODE_TEMPLATE) {
163 object->Separate();
164 return NOERR;
165 }
166 return NOERR;
167 });
168 }
169
HostInfosOutput()170 void StartupCfgGen::HostInfosOutput()
171 {
172 bool end = false;
173 uint32_t cnt = 1;
174 const uint32_t size = hostInfoMap_.size();
175
176 std::vector<std::pair<std::string, HostInfo>> vect(hostInfoMap_.begin(), hostInfoMap_.end());
177
178 using ElementType = std::pair<std::string, HostInfo>;
179 sort(vect.begin(), vect.end(), [] (const ElementType &p1, const ElementType &p2) -> bool {
180 return (p1.second.hostPriority == p2.second.hostPriority) ?
181 (p1.second.hostId < p2.second.hostId) : (p1.second.hostPriority < p2.second.hostPriority);
182 });
183
184 std::vector<std::pair<std::string, HostInfo>>::iterator it = vect.begin();
185 for (; it != vect.end(); ++it, ++cnt) {
186 if (cnt == size) {
187 end = true;
188 }
189 HostInfoOutput(it->first, end);
190 }
191 }
192
GetConfigArray(const std::shared_ptr<AstObject> & term,std::string & config)193 void StartupCfgGen::GetConfigArray(const std::shared_ptr<AstObject> &term, std::string &config)
194 {
195 if (term == nullptr) {
196 return;
197 }
198
199 std::shared_ptr<AstObject> arrayObj = term->Child();
200 if (arrayObj == nullptr) {
201 return;
202 }
203
204 uint16_t arraySize = ConfigArray::CastFrom(arrayObj)->ArraySize();
205 std::shared_ptr<AstObject> object = arrayObj->Child();
206 while (arraySize && object != nullptr) {
207 if (!object->StringValue().empty()) {
208 config.append("\"").append(object->StringValue()).append("\"");
209 if (arraySize != 1) {
210 config.append(", ");
211 }
212 }
213
214 object = object->Next();
215 arraySize--;
216 }
217 }
218
GetConfigIntArray(const std::shared_ptr<AstObject> & term,std::string & config)219 void StartupCfgGen::GetConfigIntArray(const std::shared_ptr<AstObject> &term, std::string &config)
220 {
221 if (term == nullptr) {
222 return;
223 }
224
225 std::shared_ptr<AstObject> intArrayObj = term->Child();
226 if (intArrayObj == nullptr) {
227 return;
228 }
229
230 uint16_t arraySize = ConfigArray::CastFrom(intArrayObj)->ArraySize();
231 std::shared_ptr<AstObject> object = intArrayObj->Child();
232 while (arraySize && object != nullptr) {
233 std::string value = std::to_string(object->IntegerValue());
234 config.append(value);
235 if (arraySize != 1) {
236 config.append(", ");
237 }
238
239 object = object->Next();
240 arraySize--;
241 }
242 }
243
GetProcessPriority(const std::shared_ptr<AstObject> & term,HostInfo & hostData)244 void StartupCfgGen::GetProcessPriority(const std::shared_ptr<AstObject> &term, HostInfo &hostData)
245 {
246 if (term == nullptr) {
247 return;
248 }
249
250 std::shared_ptr<AstObject> object = term->Lookup("processPriority", PARSEROP_CONFTERM);
251 if (object != nullptr) {
252 hostData.processPriority = static_cast<int32_t>(object->Child()->IntegerValue());
253 }
254 object = term->Lookup("threadPriority", PARSEROP_CONFTERM);
255 if (object != nullptr) {
256 hostData.threadPriority = static_cast<int32_t>(object->Child()->IntegerValue());
257 }
258 }
259
GetHostLoadMode(const std::shared_ptr<AstObject> & hostInfo,HostInfo & hostData)260 void StartupCfgGen::GetHostLoadMode(const std::shared_ptr<AstObject> &hostInfo, HostInfo &hostData)
261 {
262 uint32_t preload;
263 std::shared_ptr<AstObject> current = nullptr;
264 std::shared_ptr<AstObject> devNodeInfo = nullptr;
265
266 std::shared_ptr<AstObject> devInfo = hostInfo->Child();
267 while (devInfo != nullptr) {
268 if (!devInfo->IsNode()) {
269 devInfo = devInfo->Next();
270 continue;
271 }
272
273 devNodeInfo = devInfo->Child();
274 while (devNodeInfo != nullptr) {
275 current = devNodeInfo->Lookup("preload", PARSEROP_CONFTERM);
276 if (current == nullptr) {
277 devNodeInfo = devNodeInfo->Next();
278 continue;
279 }
280
281 preload = current->Child()->IntegerValue();
282 if (preload == 0 || preload == 1) {
283 hostData.dynamicLoad = false;
284 }
285
286 devNodeInfo = devNodeInfo->Next();
287 }
288 devInfo = devInfo->Next();
289 }
290 }
291
GetHostGID(const std::shared_ptr<AstObject> & term,std::string & config,const std::string & name)292 void StartupCfgGen::GetHostGID(const std::shared_ptr<AstObject> &term, std::string &config,
293 const std::string &name)
294 {
295 // get array format configuration
296 GetConfigArray(term, config);
297
298 // if the array format is not available, get the string format configuration
299 if (config.empty()) {
300 if (term != nullptr && !term->Child()->StringValue().empty()) {
301 config.append("\"").append(term->Child()->StringValue()).append("\"");
302 }
303 }
304
305 // use the default name as gid
306 if (config.empty()) {
307 config.append("\"").append(name).append("\"");
308 }
309 }
310
GetHostInfo()311 bool StartupCfgGen::GetHostInfo()
312 {
313 std::shared_ptr<AstObject> deviceInfo = ast_->GetAstRoot()->Lookup("device_info", PARSEROP_CONFNODE);
314 std::shared_ptr<AstObject> object = nullptr;
315 std::string serviceName;
316 HostInfo hostData;
317 uint32_t hostId = 0;
318
319 if (deviceInfo == nullptr) {
320 Logger().Error() << "do not find device_info node";
321 return false;
322 }
323
324 std::shared_ptr<AstObject> hostInfo = deviceInfo->Child();
325 while (hostInfo != nullptr) {
326 object = hostInfo->Lookup("hostName", PARSEROP_CONFTERM);
327 if (object == nullptr) {
328 hostInfo = hostInfo->Next();
329 continue;
330 }
331
332 InitHostInfo(hostData);
333 serviceName = object->Child()->StringValue();
334
335 object = hostInfo->Lookup("priority", PARSEROP_CONFTERM);
336 if (object != nullptr) {
337 hostData.hostPriority = object->Child()->IntegerValue();
338 }
339
340 hostData.hostUID = serviceName;
341 object = hostInfo->Lookup("uid", PARSEROP_CONFTERM);
342 if (object != nullptr && !object->Child()->StringValue().empty()) {
343 hostData.hostUID = object->Child()->StringValue();
344 }
345
346 object = hostInfo->Lookup("gid", PARSEROP_CONFTERM);
347 GetHostGID(object, hostData.hostGID, serviceName);
348
349 object = hostInfo->Lookup("caps", PARSEROP_CONFTERM);
350 GetConfigArray(object, hostData.hostCaps);
351
352 GetHostLoadMode(hostInfo, hostData);
353
354 object = hostInfo->Lookup("critical", PARSEROP_CONFTERM);
355 GetConfigIntArray(object, hostData.hostCritical);
356 GetProcessPriority(hostInfo, hostData);
357
358 object = hostInfo->Lookup("sandbox", PARSEROP_CONFTERM);
359 if (object != nullptr) {
360 hostData.sandBox = object->Child()->IntegerValue();
361 }
362
363 hostData.hostId = hostId;
364 hostInfoMap_.insert(make_pair(serviceName, hostData));
365 hostId++;
366 hostInfo = hostInfo->Next();
367 }
368 return true;
369 }
370