• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/log.h"
27 
28 using android::base::Join;
29 using android::base::Result;
30 
31 namespace android {
32 namespace linkerconfig {
33 namespace modules {
34 
WriteConfig(ConfigWriter & writer)35 void Section::WriteConfig(ConfigWriter& writer) {
36   writer.WriteLine("[" + name_ + "]");
37 
38   std::sort(namespaces_.begin(),
39             namespaces_.end(),
40             [](const auto& lhs, const auto& rhs) -> bool {
41               // make "default" a smallest one
42               if (lhs.GetName() == "default") return true;
43               if (rhs.GetName() == "default") return false;
44               return lhs.GetName() < rhs.GetName();
45             });
46 
47   if (namespaces_.size() > 1) {
48     std::vector<std::string> additional_namespaces;
49     for (const auto& ns : namespaces_) {
50       if (ns.GetName() != "default") {
51         additional_namespaces.push_back(ns.GetName());
52       }
53     }
54     writer.WriteLine("additional.namespaces = " +
55                      Join(additional_namespaces, ','));
56   }
57 
58   for (auto& ns : namespaces_) {
59     ns.WriteConfig(writer);
60   }
61 }
62 
ShouldFailOnMissingDeps(const BaseContext & ctx,const Namespace & ns)63 static bool ShouldFailOnMissingDeps(const BaseContext& ctx,
64                                     const Namespace& ns) {
65   if (!ctx.IsStrictMode()) {
66     return false;
67   }
68   // When generating for a target apex, "--strict" is applied to only the namespace
69   // for the apex to avoid failing due to missing deps in other namespaces
70   if (!ctx.GetTargetApex().empty()) {
71     return ns.GetName() == "default" || ns.GetName() == ctx.GetTargetApex();
72   }
73   return true;
74 }
75 
76 // Resolve() resolves require/provide constraints between namespaces.
77 // When foo.AddProvides({"libfoo.so"}) and bar.AddRequires({"libfoo.so"}),
78 // then Resolve() creates a linke between foo and bar:
79 //   foo.GetLink("bar").AddSharedLib({"libfoo.so"}).
80 //
81 // When a referenced lib is not provided by existing namespaces,
82 // it searches the lib in available apexes <apex_providers>
83 // and available aliases <lib_providers>, If found, new namespace is added.
Resolve(const BaseContext & ctx,const LibProviders & lib_providers)84 void Section::Resolve(const BaseContext& ctx,
85                       const LibProviders& lib_providers) {
86   // libs provided by existing namespaces
87   std::unordered_map<std::string, std::string> providers;
88   for (auto& ns : namespaces_) {
89     for (const auto& lib : ns.GetProvides()) {
90       if (auto iter = providers.find(lib); iter != providers.end()) {
91         LOG(FATAL) << fmt::format(
92             "duplicate: {} is provided by {} and {} in [{}]",
93             lib,
94             iter->second,
95             ns.GetName(),
96             name_);
97       }
98       providers[lib] = ns.GetName();
99     }
100   }
101 
102   // libs provided by apexes
103   const auto& apex_providers = ctx.GetApexModuleMap();
104 
105   // add a new namespace if not found
106   auto add_namespace = [&](auto name, auto builder) {
107     for (auto& ns : namespaces_) {
108       if (ns.GetName() == name) {
109         // it's there, we don't need to create a new one.
110         return;
111       }
112     }
113     auto new_ns = builder();
114     // Update providing library map from the new namespace
115     for (const auto& new_lib : new_ns.GetProvides()) {
116       if (providers.find(new_lib) == providers.end()) {
117         providers[new_lib] = new_ns.GetName();
118       }
119     }
120     namespaces_.push_back(std::move(new_ns));
121   };
122 
123   // Reserve enough space for namespace vector which can be increased maximum as
124   // much as potential providers. Appending new namespaces without reserving
125   // enough space from iteration can crash the process.
126   namespaces_.reserve(namespaces_.size() + ctx.GetApexModules().size() +
127                       lib_providers.size());
128 
129   auto iter = namespaces_.begin();
130   do {
131     auto& ns = *iter;
132     for (const auto& lib : ns.GetRequires()) {
133       // Search the required library in existing namespaces first <providers>,
134       // then the available apexes <apex_providers>,
135       // then the available aliases <lib_providers>
136       if (auto it = providers.find(lib); it != providers.end()) {
137         ns.GetLink(it->second).AddSharedLib(lib);
138       } else if (auto it = apex_providers.find(lib); it != apex_providers.end()) {
139         const auto& apex_info = it->second.get();
140         ns.GetLink(apex_info.namespace_name).AddSharedLib(lib);
141         // Add a new namespace for the apex
142         add_namespace(apex_info.namespace_name, [&]() {
143           return ctx.BuildApexNamespace(apex_info, false);
144         });
145       } else if (auto it = lib_providers.find(lib); it != lib_providers.end()) {
146         for (const auto& provider : it->second) {
147           // Alias is expanded to <shared_libs>.
148           // For example, ":vndk" is expanded to the list of VNDK-Core/VNDK-Sp libraries
149           ns.GetLink(provider.ns).AddSharedLib(provider.shared_libs);
150           // Add a new namespace for the alias
151           add_namespace(provider.ns, provider.ns_builder);
152         }
153       } else if (ShouldFailOnMissingDeps(ctx, ns)) {
154         LOG(FATAL) << fmt::format(
155             "not found: {} is required by {} in [{}]", lib, ns.GetName(), name_);
156       }
157     }
158     iter++;
159   } while (iter != namespaces_.end());
160 }
161 
GetNamespace(const std::string & namespace_name)162 Namespace* Section::GetNamespace(const std::string& namespace_name) {
163   for (auto& ns : namespaces_) {
164     if (ns.GetName() == namespace_name) {
165       return &ns;
166     }
167   }
168 
169   return nullptr;
170 }
171 
GetName()172 std::string Section::GetName() {
173   return name_;
174 }
175 }  // namespace modules
176 }  // namespace linkerconfig
177 }  // namespace android
178