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 void Section::WriteConfig(ConfigWriter& writer) { 35 writer.WriteLine("[" + name_ + "]"); 36 37 std::sort(namespaces_.begin(), 38 namespaces_.end(), 39 [](const auto& lhs, const auto& rhs) -> bool { 40 // make "default" a smallest one 41 if (lhs.GetName() == "default") return true; 42 if (rhs.GetName() == "default") return false; 43 return lhs.GetName() < rhs.GetName(); 44 }); 45 46 if (namespaces_.size() > 1) { 47 std::vector<std::string> additional_namespaces; 48 for (const auto& ns : namespaces_) { 49 if (ns.GetName() != "default") { 50 additional_namespaces.push_back(ns.GetName()); 51 } 52 } 53 writer.WriteLine("additional.namespaces = " + 54 Join(additional_namespaces, ',')); 55 } 56 57 for (auto& ns : namespaces_) { 58 ns.WriteConfig(writer); 59 } 60 } 61 62 Result<void> Section::Resolve(const BaseContext& ctx) { 63 std::unordered_map<std::string, std::string> providers; 64 for (auto& ns : namespaces_) { 65 for (const auto& lib : ns.GetProvides()) { 66 if (auto iter = providers.find(lib); iter != providers.end()) { 67 return Errorf("duplicate: {} is provided by {} and {} in [{}]", 68 lib, 69 iter->second, 70 ns.GetName(), 71 name_); 72 } 73 providers[lib] = ns.GetName(); 74 } 75 } 76 77 std::unordered_map<std::string, ApexInfo> candidates_providers; 78 for (const auto& apex : ctx.GetApexModules()) { 79 for (const auto& lib : apex.provide_libs) { 80 candidates_providers[lib] = apex; 81 } 82 } 83 84 // Reserve enough space for namespace vector which can be increased maximum as 85 // much as available APEX modules. Appending new namespaces without reserving 86 // enough space from iteration can crash the process. 87 namespaces_.reserve(namespaces_.size() + ctx.GetApexModules().size()); 88 89 auto iter = namespaces_.begin(); 90 do { 91 auto& ns = *iter; 92 for (const auto& lib : ns.GetRequires()) { 93 if (auto it = providers.find(lib); it != providers.end()) { 94 // If required library can be provided by existing namespaces, link to 95 // the namespace. 96 ns.GetLink(it->second).AddSharedLib(lib); 97 } else if (auto it = candidates_providers.find(lib); 98 it != candidates_providers.end()) { 99 // If required library can be provided by a APEX module, create a new 100 // namespace with the APEX and add it to this section. 101 auto new_ns = ctx.BuildApexNamespace(it->second, false); 102 103 // Update providing library map from the new namespace 104 for (const auto& new_lib : new_ns.GetProvides()) { 105 if (providers.find(new_lib) == providers.end()) { 106 providers[new_lib] = new_ns.GetName(); 107 } 108 } 109 ns.GetLink(new_ns.GetName()).AddSharedLib(lib); 110 namespaces_.push_back(std::move(new_ns)); 111 } else if (ctx.IsStrictMode()) { 112 return Errorf( 113 "not found: {} is required by {} in [{}]", lib, ns.GetName(), name_); 114 } 115 } 116 iter++; 117 } while (iter != namespaces_.end()); 118 119 return {}; 120 } 121 122 Namespace* Section::GetNamespace(const std::string& namespace_name) { 123 for (auto& ns : namespaces_) { 124 if (ns.GetName() == namespace_name) { 125 return &ns; 126 } 127 } 128 129 return nullptr; 130 } 131 132 std::string Section::GetName() { 133 return name_; 134 } 135 } // namespace modules 136 } // namespace linkerconfig 137 } // namespace android 138