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