/* * 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); } } Result Section::Resolve(const BaseContext& ctx) { 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(); } } std::unordered_map candidates_providers; for (const auto& apex : ctx.GetApexModules()) { for (const auto& lib : apex.provide_libs) { candidates_providers[lib] = apex; } } // Reserve enough space for namespace vector which can be increased maximum as // much as available APEX modules. Appending new namespaces without reserving // enough space from iteration can crash the process. namespaces_.reserve(namespaces_.size() + ctx.GetApexModules().size()); auto iter = namespaces_.begin(); do { auto& ns = *iter; for (const auto& lib : ns.GetRequires()) { if (auto it = providers.find(lib); it != providers.end()) { // If required library can be provided by existing namespaces, link to // the namespace. ns.GetLink(it->second).AddSharedLib(lib); } else if (auto it = candidates_providers.find(lib); it != candidates_providers.end()) { // If required library can be provided by a APEX module, create a new // namespace with the APEX and add it to this section. auto new_ns = ctx.BuildApexNamespace(it->second, false); // 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(); } } ns.GetLink(new_ns.GetName()).AddSharedLib(lib); namespaces_.push_back(std::move(new_ns)); } 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