• 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 #include "gn/ohos_components_mapping.h"
21 
22 /**
23  * Ohos Component API
24  *
25  * Each component belongs to one subsystem.
26  * Each component has a source path.
27  * Each component has zero or more innerapis
28  */
29 
30 static const std::string EMPTY_INNERAPI;
31 
32 static const int PATH_PREFIX_LEN = 2;
33 
34 OhosComponent::OhosComponent() = default;
35 
OhosComponent(const char * name,const char * subsystem,const char * path)36 OhosComponent::OhosComponent(const char *name, const char *subsystem, const char *path)
37 {
38     name_ = std::string(name);
39     subsystem_ = std::string(subsystem);
40     if (strncmp(path, "//", PATH_PREFIX_LEN) == 0) {
41         path_ = std::string(path);
42     } else {
43         path_ = "//" + std::string(path);
44     }
45 }
46 
addInnerApi(const std::string & name,const std::string & label)47 void OhosComponent::addInnerApi(const std::string &name, const std::string &label)
48 {
49     std::string la = label;
50     size_t pos = label.find(":");
51     if (pos != std::string::npos) {
52         if ((label[pos - 1]) == '/') { // some are like this : "//components/foo/libfoo/:libfoo"
53             unsigned long indexToRemove = pos - 1;
54             if (indexToRemove >= 0 && indexToRemove <= la.length()) {
55                 la.erase(la.begin() + indexToRemove);
56             }
57         }
58     }
59     innerapi_names_[name] = la;
60     innerapi_labels_[la] = name;
61 }
62 
63 
getInnerApi(const std::string & innerapi) const64 const std::string &OhosComponent::getInnerApi(const std::string &innerapi) const
65 {
66     if (auto res = innerapi_names_.find(innerapi); res != innerapi_names_.end()) {
67         return res->second;
68     }
69     return EMPTY_INNERAPI;
70 }
71 
isInnerApi(const std::string & label) const72 bool OhosComponent::isInnerApi(const std::string &label) const
73 {
74     if (auto res = innerapi_labels_.find(label); res != innerapi_labels_.end()) {
75         return true;
76     }
77     return false;
78 }
79 
addInnerApiVisibility(const std::string & name,const std::vector<base::Value> & list)80 void OhosComponent::addInnerApiVisibility(const std::string &name, const std::vector<base::Value> &list)
81 {
82     for (const base::Value &visibility : list) {
83         innerapi_visibility_[innerapi_names_[name]].push_back(visibility.GetString());
84     }
85 }
86 
getInnerApiVisibility(const std::string & label) const87 const std::vector<std::string> OhosComponent::getInnerApiVisibility(const std::string &label) const
88 {
89     if (auto res = innerapi_visibility_.find(label); res != innerapi_visibility_.end()) {
90         return res->second;
91     }
92     return {};
93 }
94 
95 /**
96  * Ohos Component Implimentation API
97  */
98 OhosComponentsImpl::OhosComponentsImpl() = default;
99 
ReadBuildConfigFile(const std::string & build_dir,const char * subfile,std::string & content)100 bool OhosComponentsImpl::ReadBuildConfigFile(const std::string &build_dir, const char *subfile, std::string &content)
101 {
102     std::string path = build_dir;
103     path += "/build_configs/";
104     path += subfile;
105     if (!base::ReadFileToString(base::FilePath(path), &content)) {
106         return false;
107     }
108     return true;
109 }
110 
LoadComponentInfo(const std::string & components_content,std::string & err_msg_out)111 bool OhosComponentsImpl::LoadComponentInfo(const std::string &components_content, std::string &err_msg_out)
112 {
113     const base::DictionaryValue *components_dict;
114     std::unique_ptr<base::Value> components_value = base::JSONReader::ReadAndReturnError(components_content,
115         base::JSONParserOptions::JSON_PARSE_RFC, nullptr, &err_msg_out, nullptr, nullptr);
116     if (!components_value) {
117         return false;
118     }
119     if (!components_value->GetAsDictionary(&components_dict)) {
120         return false;
121     }
122 
123     for (const auto com : components_dict->DictItems()) {
124         const base::Value *subsystem = com.second.FindKey("subsystem");
125         const base::Value *path = com.second.FindKey("path");
126         if (!subsystem || !path) {
127             continue;
128         }
129         components_[com.first] =
130             new OhosComponent(com.first.c_str(), subsystem->GetString().c_str(), path->GetString().c_str());
131         const base::Value *innerapis = com.second.FindKey("innerapis");
132         if (!innerapis) {
133             continue;
134         }
135         LoadInnerApi(com.first, innerapis->GetList());
136     }
137     setupComponentsTree();
138     return true;
139 }
140 
findChildByPath(const struct OhosComponentTree * current,const char * path,size_t len)141 const struct OhosComponentTree *OhosComponentsImpl::findChildByPath(const struct OhosComponentTree *current,
142     const char *path, size_t len)
143 {
144     if (current->child == nullptr) {
145         return nullptr;
146     }
147     const struct OhosComponentTree *item = current->child;
148     while (item != nullptr) {
149         if (strncmp(item->dirName, path, len) == 0) {
150             // Exactly matching
151             if (item->dirName[len] == '\0') {
152                 return item;
153             }
154         }
155         item = item->next;
156     }
157 
158     return nullptr;
159 }
160 
matchComponentByLabel(const char * label)161 const OhosComponent *OhosComponentsImpl::matchComponentByLabel(const char *label)
162 {
163     const struct OhosComponentTree *child;
164     const struct OhosComponentTree *current = pathTree;
165 
166     if (!label) {
167         return nullptr;
168     }
169     // Skip leading //
170     if (strncmp(label, "//", PATH_PREFIX_LEN) == 0) {
171         label += PATH_PREFIX_LEN;
172     }
173 
174     size_t len;
175     const char *sep;
176     while (label[0] != '\0') {
177         // Get next path seperator
178         sep = strchr(label, '/');
179         if (sep) {
180             len = sep - label;
181         } else {
182             // Check if it is a label with target name
183             sep = strchr(label, ':');
184             if (sep) {
185                 len = sep - label;
186             } else {
187                 len = strlen(label);
188             }
189         }
190 
191         // Match with children
192         child = findChildByPath(current, label, len);
193         if (child == nullptr) {
194             break;
195         }
196 
197         // No children, return current matched item
198         if (child->child == nullptr) {
199             return child->component;
200         }
201 
202         label += len;
203         // Finish matching if target name started
204         if (label[0] == ':') {
205             return child->component;
206         }
207 
208         // Match with child again
209         current = child;
210 
211         // Skip leading seperator
212         if (label[0] == '/') {
213             label += 1;
214         }
215     }
216 
217     return nullptr;
218 }
219 
addComponentToTree(struct OhosComponentTree * current,OhosComponent * component)220 void OhosComponentsImpl::addComponentToTree(struct OhosComponentTree *current, OhosComponent *component)
221 {
222     size_t len;
223     const char *path = component->path().c_str() + PATH_PREFIX_LEN;
224     const char *sep;
225 
226     while (path[0] != '\0') {
227         sep = strchr(path, '/');
228         if (sep) {
229             len = sep - path;
230         } else {
231             len = strlen(path);
232         }
233 
234         // Check if node already exists
235         struct OhosComponentTree *child = (struct OhosComponentTree *)findChildByPath(current, path, len);
236         if (!child) {
237             // Add intermediate node
238             child = new struct OhosComponentTree(path, len, nullptr);
239             child->next = current->child;
240             current->child = child;
241         }
242 
243         // End of path detected, setup component pointer
244         path = path + len;
245         if (path[0] == '\0') {
246             child->component = component;
247             break;
248         }
249 
250         // Continue to add next part
251         path += 1;
252         current = child;
253     }
254 }
255 
setupComponentsTree()256 void OhosComponentsImpl::setupComponentsTree()
257 {
258     pathTree = new struct OhosComponentTree("//", nullptr);
259 
260     std::map<std::string, OhosComponent *>::iterator it;
261     for (it = components_.begin(); it != components_.end(); it++) {
262         addComponentToTree(pathTree, it->second);
263     }
264 }
265 
LoadInnerApi(const std::string & component_name,const std::vector<base::Value> & innerapis)266 void OhosComponentsImpl::LoadInnerApi(const std::string &component_name, const std::vector<base::Value> &innerapis)
267 {
268     OhosComponent *component = (OhosComponent *)GetComponentByName(component_name);
269     if (!component) {
270         return;
271     }
272     for (const base::Value &kv : innerapis) {
273         const base::Value *label = kv.FindKey("label");
274         const base::Value *name = kv.FindKey("name");
275 
276         if (!label || !name) {
277             continue;
278         }
279         component->addInnerApi(name->GetString(), label->GetString());
280         const base::Value *visibility = kv.FindKey("visibility");
281         if (!visibility) {
282             continue;
283         }
284         component->addInnerApiVisibility(name->GetString(), visibility->GetList());
285     }
286 }
287 
LoadOverrideMap(const std::string & override_map)288 void OhosComponentsImpl::LoadOverrideMap(const std::string &override_map)
289 {
290     const base::DictionaryValue *override_dict;
291     std::unique_ptr<base::Value> override_value = base::JSONReader::ReadAndReturnError(override_map,
292         base::JSONParserOptions::JSON_PARSE_RFC, nullptr, nullptr, nullptr, nullptr);
293     if (!override_value) {
294         return;
295     }
296     if (!override_value->GetAsDictionary(&override_dict)) {
297         return;
298     }
299 
300     for (const auto com : override_dict->DictItems()) {
301         override_map_[com.first] = com.second.GetString();
302     }
303     return;
304 }
305 
LoadToolchain(const Value * product)306 void OhosComponentsImpl::LoadToolchain(const Value *product)
307 {
308     if (!product) {
309         return;
310     }
311     std::string path = "out/preloader/" + product->string_value() + "/build_config.json";
312     std::string content;
313     if (!base::ReadFileToString(base::FilePath(path), &content)) {
314         return;
315     }
316 
317     const base::DictionaryValue *content_dict;
318     std::unique_ptr<base::Value> content_value = base::JSONReader::ReadAndReturnError(content,
319         base::JSONParserOptions::JSON_PARSE_RFC, nullptr, nullptr, nullptr, nullptr);
320     if (!content_value) {
321         return;
322     }
323     if (!content_value->GetAsDictionary(&content_dict)) {
324         return;
325     }
326 
327     for (const auto com : content_dict->DictItems()) {
328         if (com.first == "product_toolchain_label") {
329             toolchain_ = com.second.GetString();
330             break;
331         }
332     }
333     return;
334 }
335 
LoadOhosComponents(const std::string & build_dir,const Value * enable,const Value * indep,const Value * product,Err * err)336 bool OhosComponentsImpl::LoadOhosComponents(const std::string &build_dir, const Value *enable,
337     const Value *indep, const Value *product, Err *err)
338 {
339     const char *components_file = "parts_info/components.json";
340     std::string components_content;
341     if (!ReadBuildConfigFile(build_dir, components_file, components_content)) {
342         *err = Err(*enable, "Your .gn file has enabled \"ohos_components_support\", but "
343             "OpenHarmony build config file (" +
344             std::string(components_file) + ") does not exists.\n");
345         return false;
346     }
347 
348     std::string override_map;
349     if (ReadBuildConfigFile(build_dir, "component_override_map.json", override_map)) {
350         LoadOverrideMap(override_map);
351     }
352 
353     std::string err_msg_out;
354     if (!LoadComponentInfo(components_content, err_msg_out)) {
355         *err = Err(*enable, "Your .gn file has enabled \"ohos_components_support\", but "
356             "OpenHarmony build config file parsing failed:\n" +
357             err_msg_out + "\n");
358         return false;
359     }
360     if (indep && indep->boolean_value()) {
361         is_indep_compiler_enable_ = true;
362     }
363     LoadToolchain(product);
364     return true;
365 }
366 
GetComponentByName(const std::string & component_name) const367 const OhosComponent *OhosComponentsImpl::GetComponentByName(const std::string &component_name) const
368 {
369     if (auto res = components_.find(component_name); res != components_.end()) {
370         return res->second;
371     }
372     return nullptr;
373 }
374 
GetWholeArchiveFlag(std::string str_val,int & whole_status)375 static size_t GetWholeArchiveFlag(std::string str_val, int &whole_status)
376 {
377     size_t sep_whole = str_val.find("(--whole-archive)");
378     if (sep_whole != std::string::npos) {
379         whole_status = 1;
380     } else {
381         sep_whole = str_val.find("(--no-whole-archive)");
382         if (sep_whole != std::string::npos) {
383             whole_status = 0;
384         } else {
385             whole_status = -1;
386         }
387     }
388     return sep_whole;
389 }
390 
GetPrivateDepsLabel(const Value & dep,std::string & label,const Label & current_toolchain,int & whole_status,Err * err) const391 bool OhosComponentsImpl::GetPrivateDepsLabel(const Value &dep, std::string &label,
392     const Label& current_toolchain, int &whole_status, Err *err) const
393 {
394     std::string str_val = dep.string_value();
395     size_t sep_whole = GetWholeArchiveFlag(str_val, whole_status);
396 
397     if (sep_whole != std::string::npos) {
398         label = str_val.substr(0, sep_whole);
399     } else {
400         label = str_val;
401     }
402     std::string current_toolchain_str = current_toolchain.GetUserVisibleName(false);
403     size_t tool_sep = label.find("(");
404     if (tool_sep == std::string::npos && GetTargetToolchain() != current_toolchain_str) {
405         label += "(" + current_toolchain_str + ")";
406     }
407     if (label == EMPTY_INNERAPI) {
408         *err = Err(dep,
409             "Deps label: (" + dep.string_value() + ") format error.");
410         return false;
411     }
412     return true;
413 }
414 
GetExternalDepsLabel(const Value & external_dep,std::string & label,const Label & current_toolchain,int & whole_status,Err * err) const415 bool OhosComponentsImpl::GetExternalDepsLabel(const Value &external_dep, std::string &label,
416     const Label& current_toolchain, int &whole_status, Err *err) const
417 {
418     std::string str_val = external_dep.string_value();
419     size_t sep = str_val.find(":");
420     if (sep == std::string::npos) {
421         *err = Err(external_dep, "OHOS component external_deps format error: (" + external_dep.string_value() +
422             "),"
423             "it should be a string like \"component_name:innerapi_name\".");
424         return false;
425     }
426     std::string component_name = str_val.substr(0, sep);
427     for (const auto& pair : override_map_) {
428         if (pair.first == component_name) {
429             component_name = pair.second;
430             break;
431         }
432     }
433     const OhosComponent *component = GetComponentByName(component_name);
434     if (component == nullptr) {
435         *err = Err(external_dep, "OHOS component : (" + component_name + ") not found.");
436         return false;
437     }
438 
439     std::string innerapi_name;
440     std::string tool_chain = "";
441     size_t sep_whole = GetWholeArchiveFlag(str_val, whole_status);
442     if (sep_whole != std::string::npos) {
443         innerapi_name = str_val.substr(sep + 1, sep_whole - sep - 1);
444     } else {
445         innerapi_name = str_val.substr(sep + 1);
446         size_t tool_sep = innerapi_name.find("(");
447         if (tool_sep != std::string::npos) {
448             tool_chain = innerapi_name.substr(tool_sep);
449             innerapi_name = innerapi_name.substr(0, tool_sep);
450         }
451     }
452 
453     std::string current_toolchain_str = current_toolchain.GetUserVisibleName(false);
454     if (tool_chain == "" && GetTargetToolchain() != current_toolchain_str) {
455         tool_chain = "(" + current_toolchain_str + ")";
456     }
457     if (isOhosIndepCompilerEnable()) {
458         label = component->getInnerApi(innerapi_name + tool_chain);
459         if (label == EMPTY_INNERAPI) {
460           label = component->getInnerApi(innerapi_name);
461         }
462     } else {
463         label = component->getInnerApi(innerapi_name) + tool_chain;
464     }
465 
466     if (label == EMPTY_INNERAPI) {
467         *err = Err(external_dep,
468             "OHOS innerapi: (" + innerapi_name + ") not found for component (" + component_name + ").");
469         return false;
470     }
471     return true;
472 }
473 
GetSubsystemName(const Value & component_name,std::string & subsystem_name,Err * err) const474 bool OhosComponentsImpl::GetSubsystemName(const Value &component_name, std::string &subsystem_name, Err *err) const
475 {
476     const OhosComponent *component = GetComponentByName(component_name.string_value());
477     if (component == nullptr) {
478         *err = Err(component_name, "OHOS component : (" + component_name.string_value() + ") not found.");
479         return false;
480     }
481 
482     subsystem_name = component->subsystem();
483     return true;
484 }
485 
486 /**
487  * Ohos Components Public API
488  */
489 
490 OhosComponents::OhosComponents() = default;
491 
LoadOhosComponents(const std::string & build_dir,const Value * enable,const Value * indep,const Value * product,Err * err)492 bool OhosComponents::LoadOhosComponents(const std::string &build_dir,
493     const Value *enable, const Value *indep, const Value *product, Err *err)
494 {
495     if (!enable) {
496         // Not enabled
497         return true;
498     }
499     if (!enable->VerifyTypeIs(Value::BOOLEAN, err)) {
500         return false;
501     }
502 
503     // Disabled
504     if (!enable->boolean_value()) {
505         return true;
506     }
507 
508     mgr = new OhosComponentsImpl();
509 
510     if (!mgr->LoadOhosComponents(build_dir, enable, indep, product, err)) {
511         delete mgr;
512         mgr = nullptr;
513         return false;
514     }
515 
516     return true;
517 }
518 
isOhosComponentsLoaded() const519 bool OhosComponents::isOhosComponentsLoaded() const
520 {
521     if (mgr == nullptr) {
522         return false;
523     } else {
524         return true;
525     }
526 }
527 
GetExternalDepsLabel(const Value & external_dep,std::string & label,const Label & current_toolchain,int & whole_status,Err * err) const528 bool OhosComponents::GetExternalDepsLabel(const Value &external_dep, std::string &label,
529     const Label& current_toolchain, int &whole_status, Err *err) const
530 {
531     if (!mgr) {
532         if (err) {
533             *err = Err(external_dep, "You are compiling OpenHarmony components, but \n"
534                 "\"ohos_components_support\" is not enabled or build_configs files are invalid.");
535         }
536         return false;
537     }
538     return mgr->GetExternalDepsLabel(external_dep, label, current_toolchain, whole_status, err);
539 }
540 
GetPrivateDepsLabel(const Value & dep,std::string & label,const Label & current_toolchain,int & whole_status,Err * err) const541 bool OhosComponents::GetPrivateDepsLabel(const Value &dep, std::string &label,
542     const Label& current_toolchain, int &whole_status, Err *err) const
543 {
544     if (!mgr) {
545         if (err) {
546             *err = Err(dep, "You are compiling OpenHarmony components, but \n"
547                 "\"ohos_components_support\" is not enabled or build_configs files are invalid.");
548         }
549         return false;
550     }
551     return mgr->GetPrivateDepsLabel(dep, label, current_toolchain, whole_status, err);
552 }
553 
GetSubsystemName(const Value & part_name,std::string & label,Err * err) const554 bool OhosComponents::GetSubsystemName(const Value &part_name, std::string &label, Err *err) const
555 {
556     if (!mgr) {
557         if (err) {
558             *err = Err(part_name, "You are compiling OpenHarmony components, but \n"
559                 "\"ohos_components_support\" is not enabled or build_configs files are invalid.");
560         }
561         return false;
562     }
563     return mgr->GetSubsystemName(part_name, label, err);
564 }
565 
GetComponentByLabel(const std::string & label) const566 const OhosComponent *OhosComponents::GetComponentByLabel(const std::string &label) const
567 {
568     if (!mgr) {
569         return nullptr;
570     }
571     return mgr->matchComponentByLabel(label.c_str());
572 }
573 
LoadOhosComponentsChecker(const std::string & build_dir,const Value * support,int checkType,unsigned int ruleSwitch)574 void OhosComponents::LoadOhosComponentsChecker(const std::string &build_dir, const Value *support, int checkType,
575     unsigned int ruleSwitch)
576 {
577     if (!support) {
578         return;
579     }
580     if (!support->boolean_value()) {
581         return;
582     }
583     if (checkType > OhosComponentChecker::CheckType::INTERCEPT_ALL ||
584         checkType <= OhosComponentChecker::CheckType::NONE) {
585         InnerApiPublicInfoGenerator::Init(build_dir, 0);
586         return;
587     }
588     OhosComponentChecker::Init(build_dir, checkType, ruleSwitch);
589     InnerApiPublicInfoGenerator::Init(build_dir, checkType);
590     return;
591 }
592 
LoadOhosComponentsMapping(const std::string & build_dir,const Value * support,const Value * independent)593 void OhosComponents::LoadOhosComponentsMapping(const std::string& build_dir,
594     const Value *support, const Value *independent)
595 {
596     if (!support) {
597         return;
598     }
599     if (!support->boolean_value()) {
600         return;
601     }
602 
603     if (!independent || !independent->boolean_value()) {
604         return;
605     }
606 
607     OhosComponentMapping::Init(build_dir);
608     return;
609 }
610 
GetComponentByName(const std::string & component_name)611 const OhosComponent *OhosComponents::GetComponentByName(const std::string &component_name) {
612     if (!mgr) {
613         return nullptr;
614     }
615     return mgr->GetComponentByName(component_name);
616 }
617 
isOhosIndepCompilerEnable()618 bool OhosComponents::isOhosIndepCompilerEnable() {
619     return mgr && mgr->isOhosIndepCompilerEnable();
620 }
621