blob: 8ab836869444f06d39864ca3f7e3c0b287b56b91 [file] [log] [blame]
Orion Hodson9b16e342019-10-09 13:29:16 +01001/*
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
17#define LOG_TAG "nativeloader"
18
19#include "public_libraries.h"
20
21#include <dirent.h>
22
23#include <algorithm>
24#include <memory>
25
26#include <android-base/file.h>
27#include <android-base/logging.h>
28#include <android-base/properties.h>
29#include <android-base/result.h>
30#include <android-base/strings.h>
31#include <log/log.h>
32
Justin Yun3db26d52019-12-16 14:09:39 +090033#if defined(__ANDROID__)
34#include <android/sysprop/VndkProperties.sysprop.h>
35#endif
36
Orion Hodson9b16e342019-10-09 13:29:16 +010037#include "utils.h"
38
39namespace android::nativeloader {
40
Orion Hodson9b16e342019-10-09 13:29:16 +010041using android::base::ErrnoError;
Orion Hodson9b16e342019-10-09 13:29:16 +010042using android::base::Result;
Jeffrey Huang52575032020-02-11 17:33:45 -080043using internal::ConfigEntry;
44using internal::ParseConfig;
45using std::literals::string_literals::operator""s;
Orion Hodson9b16e342019-10-09 13:29:16 +010046
47namespace {
48
49constexpr const char* kDefaultPublicLibrariesFile = "/etc/public.libraries.txt";
50constexpr const char* kExtendedPublicLibrariesFilePrefix = "public.libraries-";
51constexpr const char* kExtendedPublicLibrariesFileSuffix = ".txt";
52constexpr const char* kVendorPublicLibrariesFile = "/vendor/etc/public.libraries.txt";
53constexpr const char* kLlndkLibrariesFile = "/system/etc/llndk.libraries.txt";
54constexpr const char* kVndkLibrariesFile = "/system/etc/vndksp.libraries.txt";
55
56const std::vector<const std::string> kArtApexPublicLibraries = {
57 "libicuuc.so",
58 "libicui18n.so",
59};
60
61constexpr const char* kArtApexLibPath = "/apex/com.android.art/" LIB;
62
63constexpr const char* kNeuralNetworksApexPublicLibrary = "libneuralnetworks.so";
64
Jeffrey Huang52575032020-02-11 17:33:45 -080065constexpr const char* kStatsdApexPublicLibrary = "libstats_jni.so";
66
Orion Hodson9b16e342019-10-09 13:29:16 +010067// TODO(b/130388701): do we need this?
68std::string root_dir() {
69 static const char* android_root_env = getenv("ANDROID_ROOT");
70 return android_root_env != nullptr ? android_root_env : "/system";
71}
72
73bool debuggable() {
74 static bool debuggable = android::base::GetBoolProperty("ro.debuggable", false);
75 return debuggable;
76}
77
Justin Yun089c1352020-02-06 16:53:08 +090078std::string vndk_version_str(bool use_product_vndk) {
79 static std::string version = get_vndk_version(use_product_vndk);
Orion Hodson9b16e342019-10-09 13:29:16 +010080 if (version != "" && version != "current") {
81 return "." + version;
82 }
83 return "";
84}
85
86// For debuggable platform builds use ANDROID_ADDITIONAL_PUBLIC_LIBRARIES environment
87// variable to add libraries to the list. This is intended for platform tests only.
88std::string additional_public_libraries() {
89 if (debuggable()) {
90 const char* val = getenv("ANDROID_ADDITIONAL_PUBLIC_LIBRARIES");
91 return val ? val : "";
92 }
93 return "";
94}
95
Justin Yun089c1352020-02-06 16:53:08 +090096void InsertVndkVersionStr(std::string* file_name, bool use_product_vndk) {
Orion Hodson9b16e342019-10-09 13:29:16 +010097 CHECK(file_name != nullptr);
98 size_t insert_pos = file_name->find_last_of(".");
99 if (insert_pos == std::string::npos) {
100 insert_pos = file_name->length();
101 }
Justin Yun089c1352020-02-06 16:53:08 +0900102 file_name->insert(insert_pos, vndk_version_str(use_product_vndk));
Orion Hodson9b16e342019-10-09 13:29:16 +0100103}
104
105const std::function<Result<bool>(const struct ConfigEntry&)> always_true =
106 [](const struct ConfigEntry&) -> Result<bool> { return true; };
107
108Result<std::vector<std::string>> ReadConfig(
109 const std::string& configFile,
110 const std::function<Result<bool>(const ConfigEntry& /* entry */)>& filter_fn) {
111 std::string file_content;
112 if (!base::ReadFileToString(configFile, &file_content)) {
113 return ErrnoError();
114 }
115 Result<std::vector<std::string>> result = ParseConfig(file_content, filter_fn);
Bernie Innocenti4bd58952020-02-06 15:43:57 +0900116 if (!result.ok()) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100117 return Errorf("Cannot parse {}: {}", configFile, result.error().message());
118 }
119 return result;
120}
121
122void ReadExtensionLibraries(const char* dirname, std::vector<std::string>* sonames) {
123 std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(dirname), closedir);
124 if (dir != nullptr) {
125 // Failing to opening the dir is not an error, which can happen in
126 // webview_zygote.
127 while (struct dirent* ent = readdir(dir.get())) {
128 if (ent->d_type != DT_REG && ent->d_type != DT_LNK) {
129 continue;
130 }
131 const std::string filename(ent->d_name);
132 std::string_view fn = filename;
133 if (android::base::ConsumePrefix(&fn, kExtendedPublicLibrariesFilePrefix) &&
134 android::base::ConsumeSuffix(&fn, kExtendedPublicLibrariesFileSuffix)) {
135 const std::string company_name(fn);
136 const std::string config_file_path = dirname + "/"s + filename;
137 LOG_ALWAYS_FATAL_IF(
138 company_name.empty(),
139 "Error extracting company name from public native library list file path \"%s\"",
140 config_file_path.c_str());
141
142 auto ret = ReadConfig(
143 config_file_path, [&company_name](const struct ConfigEntry& entry) -> Result<bool> {
144 if (android::base::StartsWith(entry.soname, "lib") &&
145 android::base::EndsWith(entry.soname, "." + company_name + ".so")) {
146 return true;
147 } else {
148 return Errorf("Library name \"{}\" does not end with the company name {}.",
149 entry.soname, company_name);
150 }
151 });
Bernie Innocenti4bd58952020-02-06 15:43:57 +0900152 if (ret.ok()) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100153 sonames->insert(sonames->end(), ret->begin(), ret->end());
154 } else {
155 LOG_ALWAYS_FATAL("Error reading public native library list from \"%s\": %s",
156 config_file_path.c_str(), ret.error().message().c_str());
157 }
158 }
159 }
160 }
161}
162
163static std::string InitDefaultPublicLibraries(bool for_preload) {
164 std::string config_file = root_dir() + kDefaultPublicLibrariesFile;
165 auto sonames =
166 ReadConfig(config_file, [&for_preload](const struct ConfigEntry& entry) -> Result<bool> {
167 if (for_preload) {
168 return !entry.nopreload;
169 } else {
170 return true;
171 }
172 });
Bernie Innocenti4bd58952020-02-06 15:43:57 +0900173 if (!sonames.ok()) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100174 LOG_ALWAYS_FATAL("Error reading public native library list from \"%s\": %s",
175 config_file.c_str(), sonames.error().message().c_str());
176 return "";
177 }
178
179 std::string additional_libs = additional_public_libraries();
180 if (!additional_libs.empty()) {
181 auto vec = base::Split(additional_libs, ":");
182 std::copy(vec.begin(), vec.end(), std::back_inserter(*sonames));
183 }
184
185 // If this is for preloading libs, don't remove the libs from APEXes.
186 if (for_preload) {
187 return android::base::Join(*sonames, ':');
188 }
189
190 // Remove the public libs in the art namespace.
191 // These libs are listed in public.android.txt, but we don't want the rest of android
192 // in default namespace to dlopen the libs.
193 // For example, libicuuc.so is exposed to classloader namespace from art namespace.
194 // Unfortunately, it does not have stable C symbols, and default namespace should only use
195 // stable symbols in libandroidicu.so. http://b/120786417
196 for (const std::string& lib_name : kArtApexPublicLibraries) {
197 std::string path(kArtApexLibPath);
198 path.append("/").append(lib_name);
199
200 struct stat s;
201 // Do nothing if the path in /apex does not exist.
202 // Runtime APEX must be mounted since libnativeloader is in the same APEX
203 if (stat(path.c_str(), &s) != 0) {
204 continue;
205 }
206
207 auto it = std::find(sonames->begin(), sonames->end(), lib_name);
208 if (it != sonames->end()) {
209 sonames->erase(it);
210 }
211 }
212
213 // Remove the public libs in the nnapi namespace.
214 auto it = std::find(sonames->begin(), sonames->end(), kNeuralNetworksApexPublicLibrary);
215 if (it != sonames->end()) {
216 sonames->erase(it);
217 }
218 return android::base::Join(*sonames, ':');
219}
220
221static std::string InitArtPublicLibraries() {
Jeffrey Huang52575032020-02-11 17:33:45 -0800222 CHECK_GT((int)sizeof(kArtApexPublicLibraries), 0);
Orion Hodson9b16e342019-10-09 13:29:16 +0100223 std::string list = android::base::Join(kArtApexPublicLibraries, ":");
224
225 std::string additional_libs = additional_public_libraries();
226 if (!additional_libs.empty()) {
227 list = list + ':' + additional_libs;
228 }
229 return list;
230}
231
232static std::string InitVendorPublicLibraries() {
233 // This file is optional, quietly ignore if the file does not exist.
234 auto sonames = ReadConfig(kVendorPublicLibrariesFile, always_true);
Bernie Innocenti4bd58952020-02-06 15:43:57 +0900235 if (!sonames.ok()) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100236 return "";
237 }
238 return android::base::Join(*sonames, ':');
239}
240
Justin Yun0cc40272019-12-16 16:47:40 +0900241// read /system/etc/public.libraries-<companyname>.txt,
242// /system_ext/etc/public.libraries-<companyname>.txt and
Orion Hodson9b16e342019-10-09 13:29:16 +0100243// /product/etc/public.libraries-<companyname>.txt which contain partner defined
244// system libs that are exposed to apps. The libs in the txt files must be
245// named as lib<name>.<companyname>.so.
246static std::string InitExtendedPublicLibraries() {
247 std::vector<std::string> sonames;
248 ReadExtensionLibraries("/system/etc", &sonames);
Justin Yun0cc40272019-12-16 16:47:40 +0900249 ReadExtensionLibraries("/system_ext/etc", &sonames);
Orion Hodson9b16e342019-10-09 13:29:16 +0100250 ReadExtensionLibraries("/product/etc", &sonames);
251 return android::base::Join(sonames, ':');
252}
253
Justin Yun089c1352020-02-06 16:53:08 +0900254static std::string InitLlndkLibrariesVendor() {
Orion Hodson9b16e342019-10-09 13:29:16 +0100255 std::string config_file = kLlndkLibrariesFile;
Justin Yun089c1352020-02-06 16:53:08 +0900256 InsertVndkVersionStr(&config_file, false);
257 auto sonames = ReadConfig(config_file, always_true);
Bernie Innocentic1375632020-02-13 10:37:03 +0900258 if (!sonames.ok()) {
Justin Yun089c1352020-02-06 16:53:08 +0900259 LOG_ALWAYS_FATAL("%s", sonames.error().message().c_str());
260 return "";
261 }
262 return android::base::Join(*sonames, ':');
263}
264
265static std::string InitLlndkLibrariesProduct() {
266 std::string config_file = kLlndkLibrariesFile;
267 InsertVndkVersionStr(&config_file, true);
Orion Hodson9b16e342019-10-09 13:29:16 +0100268 auto sonames = ReadConfig(config_file, always_true);
Bernie Innocenti4bd58952020-02-06 15:43:57 +0900269 if (!sonames.ok()) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100270 LOG_ALWAYS_FATAL("%s", sonames.error().message().c_str());
271 return "";
272 }
273 return android::base::Join(*sonames, ':');
274}
275
Justin Yuneb4f08c2020-02-18 11:29:07 +0900276static std::string InitVndkspLibrariesVendor() {
Orion Hodson9b16e342019-10-09 13:29:16 +0100277 std::string config_file = kVndkLibrariesFile;
Justin Yun089c1352020-02-06 16:53:08 +0900278 InsertVndkVersionStr(&config_file, false);
Orion Hodson9b16e342019-10-09 13:29:16 +0100279 auto sonames = ReadConfig(config_file, always_true);
Bernie Innocenti4bd58952020-02-06 15:43:57 +0900280 if (!sonames.ok()) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100281 LOG_ALWAYS_FATAL("%s", sonames.error().message().c_str());
282 return "";
283 }
284 return android::base::Join(*sonames, ':');
285}
286
Justin Yuneb4f08c2020-02-18 11:29:07 +0900287static std::string InitVndkspLibrariesProduct() {
288 std::string config_file = kVndkLibrariesFile;
289 InsertVndkVersionStr(&config_file, true);
290 auto sonames = ReadConfig(config_file, always_true);
291 if (!sonames.ok()) {
292 LOG_ALWAYS_FATAL("%s", sonames.error().message().c_str());
293 return "";
294 }
295 return android::base::Join(*sonames, ':');
296}
297
Orion Hodson9b16e342019-10-09 13:29:16 +0100298static std::string InitNeuralNetworksPublicLibraries() {
299 return kNeuralNetworksApexPublicLibrary;
300}
301
Jeffrey Huang52575032020-02-11 17:33:45 -0800302static std::string InitStatsdPublicLibraries() {
303 return kStatsdApexPublicLibrary;
304}
305
Orion Hodson9b16e342019-10-09 13:29:16 +0100306} // namespace
307
308const std::string& preloadable_public_libraries() {
309 static std::string list = InitDefaultPublicLibraries(/*for_preload*/ true);
310 return list;
311}
312
313const std::string& default_public_libraries() {
314 static std::string list = InitDefaultPublicLibraries(/*for_preload*/ false);
315 return list;
316}
317
318const std::string& art_public_libraries() {
319 static std::string list = InitArtPublicLibraries();
320 return list;
321}
322
323const std::string& vendor_public_libraries() {
324 static std::string list = InitVendorPublicLibraries();
325 return list;
326}
327
328const std::string& extended_public_libraries() {
329 static std::string list = InitExtendedPublicLibraries();
330 return list;
331}
332
333const std::string& neuralnetworks_public_libraries() {
334 static std::string list = InitNeuralNetworksPublicLibraries();
335 return list;
336}
337
Jeffrey Huang52575032020-02-11 17:33:45 -0800338const std::string& statsd_public_libraries() {
339 static std::string list = InitStatsdPublicLibraries();
340 return list;
341}
342
Justin Yun089c1352020-02-06 16:53:08 +0900343const std::string& llndk_libraries_product() {
344 static std::string list = InitLlndkLibrariesProduct();
345 return list;
346}
347
348const std::string& llndk_libraries_vendor() {
349 static std::string list = InitLlndkLibrariesVendor();
Orion Hodson9b16e342019-10-09 13:29:16 +0100350 return list;
351}
352
Justin Yuneb4f08c2020-02-18 11:29:07 +0900353const std::string& vndksp_libraries_product() {
354 static std::string list = InitVndkspLibrariesProduct();
355 return list;
356}
357
358const std::string& vndksp_libraries_vendor() {
359 static std::string list = InitVndkspLibrariesVendor();
Orion Hodson9b16e342019-10-09 13:29:16 +0100360 return list;
361}
362
Justin Yun3db26d52019-12-16 14:09:39 +0900363bool is_product_vndk_version_defined() {
364#if defined(__ANDROID__)
365 return android::sysprop::VndkProperties::product_vndk_version().has_value();
366#else
367 return false;
368#endif
369}
370
Justin Yun089c1352020-02-06 16:53:08 +0900371std::string get_vndk_version(bool is_product_vndk) {
372#if defined(__ANDROID__)
373 if (is_product_vndk) {
374 return android::sysprop::VndkProperties::product_vndk_version().value_or("");
375 }
376 return android::sysprop::VndkProperties::vendor_vndk_version().value_or("");
377#else
378 if (is_product_vndk) {
379 return android::base::GetProperty("ro.product.vndk.version", "");
380 }
381 return android::base::GetProperty("ro.vndk.version", "");
382#endif
383}
384
Orion Hodson9b16e342019-10-09 13:29:16 +0100385namespace internal {
386// Exported for testing
387Result<std::vector<std::string>> ParseConfig(
388 const std::string& file_content,
389 const std::function<Result<bool>(const ConfigEntry& /* entry */)>& filter_fn) {
390 std::vector<std::string> lines = base::Split(file_content, "\n");
391
392 std::vector<std::string> sonames;
393 for (auto& line : lines) {
394 auto trimmed_line = base::Trim(line);
395 if (trimmed_line[0] == '#' || trimmed_line.empty()) {
396 continue;
397 }
398
399 std::vector<std::string> tokens = android::base::Split(trimmed_line, " ");
400 if (tokens.size() < 1 || tokens.size() > 3) {
401 return Errorf("Malformed line \"{}\"", line);
402 }
403 struct ConfigEntry entry = {.soname = "", .nopreload = false, .bitness = ALL};
404 size_t i = tokens.size();
405 while (i-- > 0) {
406 if (tokens[i] == "nopreload") {
407 entry.nopreload = true;
408 } else if (tokens[i] == "32" || tokens[i] == "64") {
409 if (entry.bitness != ALL) {
410 return Errorf("Malformed line \"{}\": bitness can be specified only once", line);
411 }
412 entry.bitness = tokens[i] == "32" ? ONLY_32 : ONLY_64;
413 } else {
414 if (i != 0) {
415 return Errorf("Malformed line \"{}\"", line);
416 }
417 entry.soname = tokens[i];
418 }
419 }
420
421 // skip 32-bit lib on 64-bit process and vice versa
422#if defined(__LP64__)
423 if (entry.bitness == ONLY_32) continue;
424#else
425 if (entry.bitness == ONLY_64) continue;
426#endif
427
428 Result<bool> ret = filter_fn(entry);
Bernie Innocenti4bd58952020-02-06 15:43:57 +0900429 if (!ret.ok()) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100430 return ret.error();
431 }
432 if (*ret) {
433 // filter_fn has returned true.
434 sonames.push_back(entry.soname);
435 }
436 }
437 return sonames;
438}
439
440} // namespace internal
441
442} // namespace android::nativeloader