• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2024 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 #include "gn/ohos_components.h"
5 
6 #include <cstring>
7 #include <iostream>
8 #include <map>
9 
10 #include "base/files/file_path.h"
11 #include "base/files/file_util.h"
12 #include "base/json/json_reader.h"
13 #include "base/values.h"
14 
15 #include "gn/err.h"
16 #include "gn/filesystem_utils.h"
17 #include "gn/innerapis_publicinfo_generator.h"
18 #include "gn/ohos_components_checker.h"
19 #include "gn/ohos_components_impl.h"
20 
21 /**
22  * Ohos Component API
23  *
24  * Each component belongs to one subsystem.
25  * Each component has a source path.
26  * Each component has zero or more innerapis
27  */
28 
29 static const std::string EMPTY_INNERAPI;
30 
31 static const int PATH_PREFIX_LEN = 2;
32 
33 OhosComponent::OhosComponent() = default;
34 
OhosComponent(const char * name,const char * subsystem,const char * path)35 OhosComponent::OhosComponent(const char *name, const char *subsystem, const char *path)
36 {
37     name_ = std::string(name);
38     subsystem_ = std::string(subsystem);
39     if (strncmp(path, "//", PATH_PREFIX_LEN) == 0) {
40         path_ = std::string(path);
41     } else {
42         path_ = "//" + std::string(path);
43     }
44 }
45 
addInnerApi(const std::string & name,const std::string & label)46 void OhosComponent::addInnerApi(const std::string &name, const std::string &label)
47 {
48     innerapi_names_[name] = label;
49     innerapi_labels_[label] = name;
50 }
51 
52 
getInnerApi(const std::string & innerapi) const53 const std::string &OhosComponent::getInnerApi(const std::string &innerapi) const
54 {
55     if (auto res = innerapi_names_.find(innerapi); res != innerapi_names_.end()) {
56         return res->second;
57     }
58     return EMPTY_INNERAPI;
59 }
60 
isInnerApi(const std::string & label) const61 bool OhosComponent::isInnerApi(const std::string &label) const
62 {
63     if (auto res = innerapi_labels_.find(label); res != innerapi_labels_.end()) {
64         return true;
65     }
66     return false;
67 }
68 
addInnerApiVisibility(const std::string & name,const std::vector<base::Value> & list)69 void OhosComponent::addInnerApiVisibility(const std::string &name, const std::vector<base::Value> &list)
70 {
71     for (const base::Value &visibility : list) {
72         innerapi_visibility_[innerapi_names_[name]].push_back(visibility.GetString());
73     }
74 }
75 
getInnerApiVisibility(const std::string & label) const76 const std::vector<std::string> OhosComponent::getInnerApiVisibility(const std::string &label) const
77 {
78     if (auto res = innerapi_visibility_.find(label); res != innerapi_visibility_.end()) {
79         return res->second;
80     }
81     return {};
82 }
83 
84 /**
85  * Ohos Component Implimentation API
86  */
87 OhosComponentsImpl::OhosComponentsImpl() = default;
88 
ReadBuildConfigFile(const std::string & build_dir,const char * subfile,std::string & content)89 bool OhosComponentsImpl::ReadBuildConfigFile(const std::string &build_dir, const char *subfile, std::string &content)
90 {
91     std::string path = build_dir;
92     path += "/build_configs/";
93     path += subfile;
94     if (!base::ReadFileToString(base::FilePath(path), &content)) {
95         return false;
96     }
97     return true;
98 }
99 
LoadComponentSubsystemAndPaths(const std::string & paths,const std::string & override_map,const std::string & subsystems,std::string & err_msg_out)100 bool OhosComponentsImpl::LoadComponentSubsystemAndPaths(const std::string &paths, const std::string &override_map,
101     const std::string &subsystems, std::string &err_msg_out)
102 {
103     const base::DictionaryValue *paths_dict;
104 
105     std::unique_ptr<base::Value> paths_value = base::JSONReader::ReadAndReturnError(paths,
106         base::JSONParserOptions::JSON_PARSE_RFC, nullptr, &err_msg_out, nullptr, nullptr);
107     if (!paths_value) {
108         return false;
109     }
110     if (!paths_value->GetAsDictionary(&paths_dict)) {
111         return false;
112     }
113 
114     const base::DictionaryValue *subsystems_dict;
115     std::unique_ptr<base::Value> subsystems_value = base::JSONReader::ReadAndReturnError(subsystems,
116         base::JSONParserOptions::JSON_PARSE_RFC, nullptr, &err_msg_out, nullptr, nullptr);
117     if (!subsystems_value) {
118         return false;
119     }
120     if (!subsystems_value->GetAsDictionary(&subsystems_dict)) {
121         return false;
122     }
123 
124     const base::Value *subsystem;
125     for (const auto com : paths_dict->DictItems()) {
126         subsystem = subsystems_dict->FindKey(com.first);
127         if (!subsystem) {
128             continue;
129         }
130         components_[com.first] =
131             new OhosComponent(com.first.c_str(), subsystem->GetString().c_str(), com.second.GetString().c_str());
132     }
133     setupComponentsTree();
134     return true;
135 }
136 
findChildByPath(const struct OhosComponentTree * current,const char * path,size_t len)137 const struct OhosComponentTree *OhosComponentsImpl::findChildByPath(const struct OhosComponentTree *current,
138     const char *path, size_t len)
139 {
140     if (current->child == nullptr) {
141         return nullptr;
142     }
143     const struct OhosComponentTree *item = current->child;
144     while (item != nullptr) {
145         if (strncmp(item->dirName, path, len) == 0) {
146             // Exactly matching
147             if (item->dirName[len] == '\0') {
148                 return item;
149             }
150         }
151         item = item->next;
152     }
153 
154     return nullptr;
155 }
156 
matchComponentByLabel(const char * label)157 const OhosComponent *OhosComponentsImpl::matchComponentByLabel(const char *label)
158 {
159     const struct OhosComponentTree *child;
160     const struct OhosComponentTree *current = pathTree;
161 
162     if (!label) {
163         return nullptr;
164     }
165     // Skip leading //
166     if (strncmp(label, "//", PATH_PREFIX_LEN) == 0) {
167         label += PATH_PREFIX_LEN;
168     }
169 
170     size_t len;
171     const char *sep;
172     while (label[0] != '\0') {
173         // Get next path seperator
174         sep = strchr(label, '/');
175         if (sep) {
176             len = sep - label;
177         } else {
178             // Check if it is a label with target name
179             sep = strchr(label, ':');
180             if (sep) {
181                 len = sep - label;
182             } else {
183                 len = strlen(label);
184             }
185         }
186 
187         // Match with children
188         child = findChildByPath(current, label, len);
189         if (child == nullptr) {
190             break;
191         }
192 
193         // No children, return current matched item
194         if (child->child == nullptr) {
195             return child->component;
196         }
197 
198         label += len;
199         // Finish matching if target name started
200         if (label[0] == ':') {
201             return child->component;
202         }
203 
204         // Match with child again
205         current = child;
206 
207         // Skip leading seperator
208         if (label[0] == '/') {
209             label += 1;
210         }
211     }
212 
213     return nullptr;
214 }
215 
addComponentToTree(struct OhosComponentTree * current,OhosComponent * component)216 void OhosComponentsImpl::addComponentToTree(struct OhosComponentTree *current, OhosComponent *component)
217 {
218     size_t len;
219     const char *path = component->path().c_str() + PATH_PREFIX_LEN;
220     const char *sep;
221 
222     while (path[0] != '\0') {
223         sep = strchr(path, '/');
224         if (sep) {
225             len = sep - path;
226         } else {
227             len = strlen(path);
228         }
229 
230         // Check if node already exists
231         struct OhosComponentTree *child = (struct OhosComponentTree *)findChildByPath(current, path, len);
232         if (!child) {
233             // Add intermediate node
234             child = new struct OhosComponentTree(path, len, nullptr);
235             child->next = current->child;
236             current->child = child;
237         }
238 
239         // End of path detected, setup component pointer
240         path = path + len;
241         if (path[0] == '\0') {
242             child->component = component;
243             break;
244         }
245 
246         // Continue to add next part
247         path += 1;
248         current = child;
249     }
250 }
251 
setupComponentsTree()252 void OhosComponentsImpl::setupComponentsTree()
253 {
254     pathTree = new struct OhosComponentTree("//", nullptr);
255 
256     std::map<std::string, OhosComponent *>::iterator it;
257     for (it = components_.begin(); it != components_.end(); it++) {
258         addComponentToTree(pathTree, it->second);
259     }
260 }
261 
LoadInnerApi(const base::DictionaryValue * innerapis)262 void OhosComponentsImpl::LoadInnerApi(const base::DictionaryValue *innerapis)
263 {
264     OhosComponent *component;
265     for (const auto kv : innerapis->DictItems()) {
266         for (const auto inner : kv.second.DictItems()) {
267             component = (OhosComponent *)GetComponentByName(kv.first);
268             if (!component) {
269                 break;
270             }
271             for (const auto info : inner.second.DictItems()) {
272                 if (info.first == "label") {
273                     component->addInnerApi(inner.first, info.second.GetString());
274                     break;
275                 }
276             }
277             for (const auto info : inner.second.DictItems()) {
278                 if (info.first == "visibility") {
279                     component->addInnerApiVisibility(inner.first, info.second.GetList());
280                     break;
281                 }
282             }
283         }
284     }
285 }
286 
LoadOhosInnerApis_(const std::string innerapi_content,std::string & err_msg_out)287 bool OhosComponentsImpl::LoadOhosInnerApis_(const std::string innerapi_content, std::string &err_msg_out)
288 {
289     const base::DictionaryValue *innerapis_dict;
290 
291     std::unique_ptr<base::Value> innerapis = base::JSONReader::ReadAndReturnError(innerapi_content,
292         base::JSONParserOptions::JSON_PARSE_RFC, nullptr, &err_msg_out, nullptr, nullptr);
293     if (!innerapis) {
294         return false;
295     }
296     if (!innerapis->GetAsDictionary(&innerapis_dict)) {
297         return false;
298     }
299     LoadInnerApi(innerapis_dict);
300     return true;
301 }
302 
LoadOhosComponents(const std::string & build_dir,const Value * enable,Err * err)303 bool OhosComponentsImpl::LoadOhosComponents(const std::string &build_dir, const Value *enable, Err *err)
304 {
305     const char *paths_file = "parts_info/parts_path_info.json";
306     std::string paths_content;
307     if (!ReadBuildConfigFile(build_dir, paths_file, paths_content)) {
308         *err = Err(*enable, "Your .gn file has enabled \"ohos_components_support\", but "
309             "OpenHarmony build config file (" +
310             std::string(paths_file) + ") does not exists.\n");
311         return false;
312     }
313     const char *subsystems_file = "parts_info/part_subsystem.json";
314     std::string subsystems_content;
315     if (!ReadBuildConfigFile(build_dir, subsystems_file, subsystems_content)) {
316         *err = Err(*enable, "Your .gn file has enabled \"ohos_components_support\", but "
317             "OpenHarmony build config file (" +
318             std::string(subsystems_file) + ") does not exists.\n");
319         return false;
320     }
321     const char *innerapis_file = "parts_info/inner_kits_info.json";
322     std::string innerapis_content;
323     if (!ReadBuildConfigFile(build_dir, innerapis_file, innerapis_content)) {
324         *err = Err(*enable, "Your .gn file has enabled \"ohos_components_support\", but "
325             "OpenHarmony build config file (" +
326             std::string(innerapis_file) + ") does not exists.\n");
327         return false;
328     }
329     const char *override_file = "component_override_map.json";
330     std::string override_map;
331     if (!ReadBuildConfigFile(build_dir, override_file, override_map)) {
332         override_map = EMPTY_INNERAPI;
333     }
334     std::string err_msg_out;
335     if (!LoadComponentSubsystemAndPaths(paths_content, override_map, subsystems_content, err_msg_out)) {
336         *err = Err(*enable, "Your .gn file has enabled \"ohos_components_support\", but "
337             "OpenHarmony build config file parsing failed:\n" +
338             err_msg_out + "\n");
339         return false;
340     }
341     if (!LoadOhosInnerApis_(innerapis_content, err_msg_out)) {
342         *err = Err(*enable, "Your .gn file has enabled \"ohos_components_support\", but "
343             "OpenHarmony build config file " +
344             std::string(innerapis_file) + " parsing failed:\n" + err_msg_out + "\n");
345         return false;
346     }
347     return true;
348 }
349 
GetComponentByName(const std::string & component_name) const350 const OhosComponent *OhosComponentsImpl::GetComponentByName(const std::string &component_name) const
351 {
352     if (auto res = components_.find(component_name); res != components_.end()) {
353         return res->second;
354     }
355     return nullptr;
356 }
357 
GetExternalDepsLabel(const Value & external_dep,std::string & label,Err * err) const358 bool OhosComponentsImpl::GetExternalDepsLabel(const Value &external_dep, std::string &label, Err *err) const
359 {
360     std::string str_val = external_dep.string_value();
361     size_t sep = str_val.find(":");
362     if (sep <= 0) {
363         *err = Err(external_dep, "OHOS component external_deps format error: (" + external_dep.string_value() +
364             "),"
365             "it should be a string like \"component_name:innerapi_name\".");
366         return false;
367     }
368     std::string component_name = str_val.substr(0, sep);
369     const OhosComponent *component = GetComponentByName(component_name);
370     if (component == nullptr) {
371         *err = Err(external_dep, "OHOS component : (" + component_name + ") not found.");
372         return false;
373     }
374     std::string innerapi_name = str_val.substr(sep + 1);
375     label = component->getInnerApi(innerapi_name);
376     if (label == EMPTY_INNERAPI) {
377         *err = Err(external_dep,
378             "OHOS innerapi: (" + innerapi_name + ") not found for component (" + component_name + ").");
379         return false;
380     }
381     return true;
382 }
383 
GetSubsystemName(const Value & component_name,std::string & subsystem_name,Err * err) const384 bool OhosComponentsImpl::GetSubsystemName(const Value &component_name, std::string &subsystem_name, Err *err) const
385 {
386     const OhosComponent *component = GetComponentByName(component_name.string_value());
387     if (component == nullptr) {
388         *err = Err(component_name, "OHOS component : (" + component_name.string_value() + ") not found.");
389         return false;
390     }
391 
392     subsystem_name = component->subsystem();
393     return true;
394 }
395 
396 /**
397  * Ohos Components Public API
398  */
399 
400 OhosComponents::OhosComponents() = default;
401 
LoadOhosComponents(const std::string & build_dir,const Value * enable,Err * err)402 bool OhosComponents::LoadOhosComponents(const std::string &build_dir, const Value *enable, Err *err)
403 {
404     if (!enable) {
405         // Not enabled
406         return true;
407     }
408     if (!enable->VerifyTypeIs(Value::BOOLEAN, err)) {
409         return false;
410     }
411 
412     // Disabled
413     if (!enable->boolean_value()) {
414         return true;
415     }
416 
417     mgr = new OhosComponentsImpl();
418 
419     if (!mgr->LoadOhosComponents(build_dir, enable, err)) {
420         delete mgr;
421         mgr = nullptr;
422         return false;
423     }
424 
425     return true;
426 }
427 
isOhosComponentsLoaded() const428 bool OhosComponents::isOhosComponentsLoaded() const
429 {
430     if (mgr == nullptr) {
431         return false;
432     } else {
433         return true;
434     }
435 }
436 
GetExternalDepsLabel(const Value & external_dep,std::string & label,Err * err) const437 bool OhosComponents::GetExternalDepsLabel(const Value &external_dep, std::string &label, Err *err) const
438 {
439     if (!mgr) {
440         if (err) {
441             *err = Err(external_dep, "You are compiling OpenHarmony components, but \n"
442                 "\"ohos_components_support\" is not enabled or build_configs files are invalid.");
443         }
444         return false;
445     }
446     return mgr->GetExternalDepsLabel(external_dep, label, err);
447 }
448 
GetSubsystemName(const Value & part_name,std::string & label,Err * err) const449 bool OhosComponents::GetSubsystemName(const Value &part_name, std::string &label, Err *err) const
450 {
451     if (!mgr) {
452         if (err) {
453             *err = Err(part_name, "You are compiling OpenHarmony components, but \n"
454                 "\"ohos_components_support\" is not enabled or build_configs files are invalid.");
455         }
456         return false;
457     }
458     return mgr->GetSubsystemName(part_name, label, err);
459 }
460 
GetComponentByLabel(const std::string & label) const461 const OhosComponent *OhosComponents::GetComponentByLabel(const std::string &label) const
462 {
463     if (!mgr) {
464         return nullptr;
465     }
466     return mgr->matchComponentByLabel(label.c_str());
467 }
468 
LoadOhosComponentsChecker(const std::string & build_dir,const Value * support,int checkType)469 void OhosComponents::LoadOhosComponentsChecker(const std::string &build_dir, const Value *support, int checkType)
470 {
471     if (!support) {
472         return;
473     }
474     if (!support->boolean_value()) {
475         return;
476     }
477     if (checkType > OhosComponentChecker::CheckType::INTERCEPT_ALL ||
478         checkType <= OhosComponentChecker::CheckType::NONE) {
479         InnerApiPublicInfoGenerator::Init(build_dir, 0);
480         return;
481     }
482     OhosComponentChecker::Init(build_dir, checkType);
483     InnerApiPublicInfoGenerator::Init(build_dir, checkType);
484     return;
485 }
486