xref: /aosp_15_r20/system/linkerconfig/modules/section.cc (revision e5eeaa8e05bc25a862c0c861bda7c8a6bfb42dad)
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "linkerconfig/section.h"
17 
18 #include <algorithm>
19 #include <functional>
20 #include <unordered_map>
21 #include <utility>
22 
23 #include <android-base/result.h>
24 #include <android-base/strings.h>
25 
26 #include "linkerconfig/environment.h"
27 #include "linkerconfig/log.h"
28 
29 using android::base::Join;
30 using android::base::Result;
31 
32 namespace android {
33 namespace linkerconfig {
34 namespace modules {
35 
WriteConfig(ConfigWriter & writer) const36 void Section::WriteConfig(ConfigWriter& writer) const {
37   writer.WriteLine("[" + name_ + "]");
38 
39   if (namespaces_.size() > 1) {
40     std::vector<std::string> additional_namespaces;
41     for (const auto& ns : namespaces_) {
42       if (ns.GetName() != "default") {
43         additional_namespaces.push_back(ns.GetName());
44       }
45     }
46     writer.WriteLine("additional.namespaces = " +
47                      Join(additional_namespaces, ','));
48   }
49 
50   for (const auto& ns : namespaces_) {
51     ns.WriteConfig(writer);
52   }
53 }
54 
ShouldFailOnMissingDeps(const BaseContext & ctx,const Namespace & ns)55 static bool ShouldFailOnMissingDeps(const BaseContext& ctx,
56                                     const Namespace& ns) {
57   if (!ctx.IsStrictMode()) {
58     return false;
59   }
60   // When generating for a target apex, "--strict" is applied to only the namespace
61   // for the apex to avoid failing due to missing deps in other namespaces
62   if (!ctx.GetTargetApex().empty()) {
63     return ns.GetName() == "default" || ns.GetName() == ctx.GetTargetApex();
64   }
65   return true;
66 }
67 
68 // Resolve() resolves require/provide constraints between namespaces.
69 // When foo.AddProvides({"libfoo.so"}) and bar.AddRequires({"libfoo.so"}),
70 // then Resolve() creates a linke between foo and bar:
71 //   foo.GetLink("bar").AddSharedLib({"libfoo.so"}).
72 //
73 // When a referenced lib is not provided by existing namespaces,
74 // it searches the lib in available apexes <apex_providers>
75 // and available aliases <lib_providers>, If found, new namespace is added.
Resolve(const BaseContext & ctx,const LibProviders & lib_providers)76 void Section::Resolve(const BaseContext& ctx,
77                       const LibProviders& lib_providers) {
78   // libs provided by existing namespaces
79   std::unordered_map<std::string, std::string> providers;
80   for (auto& ns : namespaces_) {
81     for (const auto& lib : ns.GetProvides()) {
82       if (auto iter = providers.find(lib); iter != providers.end()) {
83         LOG(android::base::FATAL)
84             << fmt::format("duplicate: {} is provided by {} and {} in [{}]",
85                            lib,
86                            iter->second,
87                            ns.GetName(),
88                            name_);
89       } else {
90         providers[lib] = ns.GetName();
91       }
92     }
93   }
94 
95   // libs provided by apexes
96   const auto& apex_providers = ctx.GetApexModuleMap();
97 
98   // add a new namespace if not found
99   auto add_namespace = [&](auto name, auto builder) {
100     for (auto& ns : namespaces_) {
101       if (ns.GetName() == name) {
102         // it's there, we don't need to create a new one.
103         return;
104       }
105     }
106     auto new_ns = builder();
107     // Update providing library map from the new namespace
108     for (const auto& new_lib : new_ns.GetProvides()) {
109       if (providers.find(new_lib) == providers.end()) {
110         providers[new_lib] = new_ns.GetName();
111       }
112     }
113     namespaces_.push_back(std::move(new_ns));
114   };
115 
116   // Reserve enough space for namespace vector which can be increased maximum as
117   // much as potential providers. Appending new namespaces without reserving
118   // enough space from iteration can crash the process.
119   namespaces_.reserve(namespaces_.size() + ctx.GetApexModules().size() +
120                       lib_providers.size());
121 
122   auto iter = namespaces_.begin();
123   do {
124     auto& ns = *iter;
125     for (const auto& lib : ns.GetRequires()) {
126       // Search the required library in existing namespaces first <providers>,
127       // then the available apexes <apex_providers>,
128       // then the available aliases <lib_providers>
129       if (auto it = providers.find(lib); it != providers.end()) {
130         ns.GetLink(it->second).AddSharedLib(lib);
131       } else if (auto it = apex_providers.find(lib); it != apex_providers.end()) {
132         const auto& apex_info = it->second.get();
133         ns.GetLink(apex_info.namespace_name).AddSharedLib(lib);
134         // Add a new namespace for the apex
135         add_namespace(apex_info.namespace_name, [&]() {
136           return ctx.BuildApexNamespace(apex_info, false);
137         });
138       } else if (auto it = lib_providers.find(lib); it != lib_providers.end()) {
139         for (const auto& provider : it->second) {
140           // Alias is expanded to <shared_libs>.
141           // For example, ":vndk" is expanded to the list of VNDK-Core/VNDK-Sp libraries
142           std::visit([&](auto&& mod) { mod.Apply(ns.GetLink(provider.ns)); },
143                      provider.link_modifier);
144           // Add a new namespace for the alias
145           add_namespace(provider.ns, provider.ns_builder);
146         }
147       } else if (ShouldFailOnMissingDeps(ctx, ns)) {
148         LOG(FATAL) << fmt::format(
149             "not found: {} is required by {} in [{}]", lib, ns.GetName(), name_);
150       }
151     }
152     iter++;
153   } while (iter != namespaces_.end());
154 
155   std::sort(namespaces_.begin(),
156             namespaces_.end(),
157             [](const auto& lhs, const auto& rhs) -> bool {
158               // make "default" a smallest one
159               if (lhs.GetName() == "default") return true;
160               if (rhs.GetName() == "default") return false;
161               return lhs.GetName() < rhs.GetName();
162             });
163 }
164 
GetNamespace(const std::string & namespace_name)165 Namespace* Section::GetNamespace(const std::string& namespace_name) {
166   for (auto& ns : namespaces_) {
167     if (ns.GetName() == namespace_name) {
168       return &ns;
169     }
170   }
171 
172   return nullptr;
173 }
174 
GetName()175 std::string Section::GetName() {
176   return name_;
177 }
178 }  // namespace modules
179 }  // namespace linkerconfig
180 }  // namespace android
181