/* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "linkerconfig/section.h" #include #include #include #include #include #include #include "linkerconfig/log.h" using android::base::Join; using android::base::Result; namespace android { namespace linkerconfig { namespace modules { void Section::WriteConfig(ConfigWriter& writer) { writer.WriteLine("[" + name_ + "]"); std::sort(namespaces_.begin(), namespaces_.end(), [](const auto& lhs, const auto& rhs) -> bool { // make "default" a smallest one if (lhs.GetName() == "default") return true; if (rhs.GetName() == "default") return false; return lhs.GetName() < rhs.GetName(); }); if (namespaces_.size() > 1) { std::vector additional_namespaces; for (const auto& ns : namespaces_) { if (ns.GetName() != "default") { additional_namespaces.push_back(ns.GetName()); } } writer.WriteLine("additional.namespaces = " + Join(additional_namespaces, ',')); } for (auto& ns : namespaces_) { ns.WriteConfig(writer); } } // Resolve() resolves require/provide constraints between namespaces. // When foo.AddProvides({"libfoo.so"}) and bar.AddRequires({"libfoo.so"}), // then Resolve() creates a linke between foo and bar: // foo.GetLink("bar").AddSharedLib({"libfoo.so"}). // // When a referenced lib is not provided by existing namespaces, // it searches the lib in available apexes // and available aliases , If found, new namespace is added. Result Section::Resolve(const BaseContext& ctx, const LibProviders& lib_providers) { // libs provided by existing namespaces std::unordered_map providers; for (auto& ns : namespaces_) { for (const auto& lib : ns.GetProvides()) { if (auto iter = providers.find(lib); iter != providers.end()) { return Errorf("duplicate: {} is provided by {} and {} in [{}]", lib, iter->second, ns.GetName(), name_); } providers[lib] = ns.GetName(); } } // libs provided by apexes std::unordered_map apex_providers; for (const auto& apex : ctx.GetApexModules()) { for (const auto& lib : apex.provide_libs) { apex_providers[lib] = apex; } } // add a new namespace if not found auto add_namespace = [&](auto name, auto builder) { for (auto& ns : namespaces_) { if (ns.GetName() == name) { // it's there, we don't need to create a new one. return; } } auto new_ns = builder(); // Update providing library map from the new namespace for (const auto& new_lib : new_ns.GetProvides()) { if (providers.find(new_lib) == providers.end()) { providers[new_lib] = new_ns.GetName(); } } namespaces_.push_back(std::move(new_ns)); }; // Reserve enough space for namespace vector which can be increased maximum as // much as potential providers. Appending new namespaces without reserving // enough space from iteration can crash the process. namespaces_.reserve(namespaces_.size() + ctx.GetApexModules().size() + lib_providers.size()); auto iter = namespaces_.begin(); do { auto& ns = *iter; for (const auto& lib : ns.GetRequires()) { // Search the required library in existing namespaces first , // then the available apexes , // then the available aliases if (auto it = providers.find(lib); it != providers.end()) { ns.GetLink(it->second).AddSharedLib(lib); } else if (auto it = apex_providers.find(lib); it != apex_providers.end()) { ns.GetLink(it->second.namespace_name).AddSharedLib(lib); // Add a new namespace for the apex add_namespace(it->second.namespace_name, [&]() { return ctx.BuildApexNamespace(it->second, false); }); } else if (auto it = lib_providers.find(lib); it != lib_providers.end()) { // Alias is expanded to . // For example, ":vndk" is expanded to the list of VNDK-Core/VNDK-Sp libraries ns.GetLink(it->second.ns).AddSharedLib(it->second.shared_libs); // Add a new namespace for the alias add_namespace(it->second.ns, it->second.ns_builder); } else if (ctx.IsStrictMode()) { return Errorf( "not found: {} is required by {} in [{}]", lib, ns.GetName(), name_); } } iter++; } while (iter != namespaces_.end()); return {}; } Namespace* Section::GetNamespace(const std::string& namespace_name) { for (auto& ns : namespaces_) { if (ns.GetName() == namespace_name) { return &ns; } } return nullptr; } std::string Section::GetName() { return name_; } } // namespace modules } // namespace linkerconfig } // namespace android