• 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     } else {
460         label = component->getInnerApi(innerapi_name) + tool_chain;
461     }
462 
463     if (label == EMPTY_INNERAPI) {
464         *err = Err(external_dep,
465             "OHOS innerapi: (" + innerapi_name + ") not found for component (" + component_name + ").");
466         return false;
467     }
468     return true;
469 }
470 
GetSubsystemName(const Value & component_name,std::string & subsystem_name,Err * err) const471 bool OhosComponentsImpl::GetSubsystemName(const Value &component_name, std::string &subsystem_name, Err *err) const
472 {
473     const OhosComponent *component = GetComponentByName(component_name.string_value());
474     if (component == nullptr) {
475         *err = Err(component_name, "OHOS component : (" + component_name.string_value() + ") not found.");
476         return false;
477     }
478 
479     subsystem_name = component->subsystem();
480     return true;
481 }
482 
483 /**
484  * Ohos Components Public API
485  */
486 
487 OhosComponents::OhosComponents() = default;
488 
LoadOhosComponents(const std::string & build_dir,const Value * enable,const Value * indep,const Value * product,Err * err)489 bool OhosComponents::LoadOhosComponents(const std::string &build_dir,
490     const Value *enable, const Value *indep, const Value *product, Err *err)
491 {
492     if (!enable) {
493         // Not enabled
494         return true;
495     }
496     if (!enable->VerifyTypeIs(Value::BOOLEAN, err)) {
497         return false;
498     }
499 
500     // Disabled
501     if (!enable->boolean_value()) {
502         return true;
503     }
504 
505     mgr = new OhosComponentsImpl();
506 
507     if (!mgr->LoadOhosComponents(build_dir, enable, indep, product, err)) {
508         delete mgr;
509         mgr = nullptr;
510         return false;
511     }
512 
513     return true;
514 }
515 
isOhosComponentsLoaded() const516 bool OhosComponents::isOhosComponentsLoaded() const
517 {
518     if (mgr == nullptr) {
519         return false;
520     } else {
521         return true;
522     }
523 }
524 
GetExternalDepsLabel(const Value & external_dep,std::string & label,const Label & current_toolchain,int & whole_status,Err * err) const525 bool OhosComponents::GetExternalDepsLabel(const Value &external_dep, std::string &label,
526     const Label& current_toolchain, int &whole_status, Err *err) const
527 {
528     if (!mgr) {
529         if (err) {
530             *err = Err(external_dep, "You are compiling OpenHarmony components, but \n"
531                 "\"ohos_components_support\" is not enabled or build_configs files are invalid.");
532         }
533         return false;
534     }
535     return mgr->GetExternalDepsLabel(external_dep, label, current_toolchain, whole_status, err);
536 }
537 
GetPrivateDepsLabel(const Value & dep,std::string & label,const Label & current_toolchain,int & whole_status,Err * err) const538 bool OhosComponents::GetPrivateDepsLabel(const Value &dep, std::string &label,
539     const Label& current_toolchain, int &whole_status, Err *err) const
540 {
541     if (!mgr) {
542         if (err) {
543             *err = Err(dep, "You are compiling OpenHarmony components, but \n"
544                 "\"ohos_components_support\" is not enabled or build_configs files are invalid.");
545         }
546         return false;
547     }
548     return mgr->GetPrivateDepsLabel(dep, label, current_toolchain, whole_status, err);
549 }
550 
GetSubsystemName(const Value & part_name,std::string & label,Err * err) const551 bool OhosComponents::GetSubsystemName(const Value &part_name, std::string &label, Err *err) const
552 {
553     if (!mgr) {
554         if (err) {
555             *err = Err(part_name, "You are compiling OpenHarmony components, but \n"
556                 "\"ohos_components_support\" is not enabled or build_configs files are invalid.");
557         }
558         return false;
559     }
560     return mgr->GetSubsystemName(part_name, label, err);
561 }
562 
GetComponentByLabel(const std::string & label) const563 const OhosComponent *OhosComponents::GetComponentByLabel(const std::string &label) const
564 {
565     if (!mgr) {
566         return nullptr;
567     }
568     return mgr->matchComponentByLabel(label.c_str());
569 }
570 
LoadOhosComponentsChecker(const std::string & build_dir,const Value * support,int checkType,unsigned int ruleSwitch)571 void OhosComponents::LoadOhosComponentsChecker(const std::string &build_dir, const Value *support, int checkType,
572     unsigned int ruleSwitch)
573 {
574     if (!support) {
575         return;
576     }
577     if (!support->boolean_value()) {
578         return;
579     }
580     if (checkType > OhosComponentChecker::CheckType::INTERCEPT_ALL ||
581         checkType <= OhosComponentChecker::CheckType::NONE) {
582         InnerApiPublicInfoGenerator::Init(build_dir, 0);
583         return;
584     }
585     OhosComponentChecker::Init(build_dir, checkType, ruleSwitch);
586     InnerApiPublicInfoGenerator::Init(build_dir, checkType);
587     return;
588 }
589 
LoadOhosComponentsMapping(const std::string & build_dir,const Value * support,const Value * independent)590 void OhosComponents::LoadOhosComponentsMapping(const std::string& build_dir,
591     const Value *support, const Value *independent)
592 {
593     if (!support) {
594         return;
595     }
596     if (!support->boolean_value()) {
597         return;
598     }
599 
600     if (!independent || !independent->boolean_value()) {
601         return;
602     }
603 
604     OhosComponentMapping::Init(build_dir);
605     return;
606 }