blob: 7bb5a1fde2da3449e051e95c4fb6971a8b67ca3f [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>
Jooyung Han538f99a2020-03-03 00:46:50 +090024#include <map>
Orion Hodson9b16e342019-10-09 13:29:16 +010025#include <memory>
26
27#include <android-base/file.h>
28#include <android-base/logging.h>
29#include <android-base/properties.h>
30#include <android-base/result.h>
31#include <android-base/strings.h>
32#include <log/log.h>
33
Nicolas Geoffray7ca8b672020-04-24 15:43:48 +010034#if defined(ART_TARGET_ANDROID)
Justin Yun3db26d52019-12-16 14:09:39 +090035#include <android/sysprop/VndkProperties.sysprop.h>
36#endif
37
Orion Hodson9b16e342019-10-09 13:29:16 +010038#include "utils.h"
39
40namespace android::nativeloader {
41
Orion Hodson9b16e342019-10-09 13:29:16 +010042using android::base::ErrnoError;
Orion Hodson9b16e342019-10-09 13:29:16 +010043using android::base::Result;
Jeffrey Huang52575032020-02-11 17:33:45 -080044using internal::ConfigEntry;
45using internal::ParseConfig;
Jooyung Han538f99a2020-03-03 00:46:50 +090046using internal::ParseJniConfig;
Jeffrey Huang52575032020-02-11 17:33:45 -080047using std::literals::string_literals::operator""s;
Orion Hodson9b16e342019-10-09 13:29:16 +010048
49namespace {
50
51constexpr const char* kDefaultPublicLibrariesFile = "/etc/public.libraries.txt";
52constexpr const char* kExtendedPublicLibrariesFilePrefix = "public.libraries-";
53constexpr const char* kExtendedPublicLibrariesFileSuffix = ".txt";
Jooyung Han538f99a2020-03-03 00:46:50 +090054constexpr const char* kJniConfigFile = "/linkerconfig/jni.config.txt";
Orion Hodson9b16e342019-10-09 13:29:16 +010055constexpr const char* kVendorPublicLibrariesFile = "/vendor/etc/public.libraries.txt";
Jooyung Han26f7d102020-02-22 23:39:23 +090056constexpr const char* kLlndkLibrariesFile = "/apex/com.android.vndk.v{}/etc/llndk.libraries.{}.txt";
57constexpr const char* kVndkLibrariesFile = "/apex/com.android.vndk.v{}/etc/vndksp.libraries.{}.txt";
Orion Hodson9b16e342019-10-09 13:29:16 +010058
59const std::vector<const std::string> kArtApexPublicLibraries = {
vichang4a487752020-05-05 11:11:30 +000060 "libicuuc.so",
61 "libicui18n.so",
Orion Hodsone33dca62020-04-28 14:07:58 +010062 "libnativehelper.so",
Orion Hodson9b16e342019-10-09 13:29:16 +010063};
64
vichang4a487752020-05-05 11:11:30 +000065constexpr const char* kArtApexLibPath = "/apex/com.android.art/" LIB;
Orion Hodson9b16e342019-10-09 13:29:16 +010066
67constexpr const char* kNeuralNetworksApexPublicLibrary = "libneuralnetworks.so";
68
Jeffrey Huang52575032020-02-11 17:33:45 -080069constexpr const char* kStatsdApexPublicLibrary = "libstats_jni.so";
70
Orion Hodson9b16e342019-10-09 13:29:16 +010071// TODO(b/130388701): do we need this?
72std::string root_dir() {
73 static const char* android_root_env = getenv("ANDROID_ROOT");
74 return android_root_env != nullptr ? android_root_env : "/system";
75}
76
77bool debuggable() {
78 static bool debuggable = android::base::GetBoolProperty("ro.debuggable", false);
79 return debuggable;
80}
81
Justin Yun089c1352020-02-06 16:53:08 +090082std::string vndk_version_str(bool use_product_vndk) {
Jooyung Han26f7d102020-02-22 23:39:23 +090083 if (use_product_vndk) {
84 static std::string product_vndk_version = get_vndk_version(true);
85 return product_vndk_version;
86 } else {
87 static std::string vendor_vndk_version = get_vndk_version(false);
88 return vendor_vndk_version;
Orion Hodson9b16e342019-10-09 13:29:16 +010089 }
Orion Hodson9b16e342019-10-09 13:29:16 +010090}
91
92// For debuggable platform builds use ANDROID_ADDITIONAL_PUBLIC_LIBRARIES environment
93// variable to add libraries to the list. This is intended for platform tests only.
94std::string additional_public_libraries() {
95 if (debuggable()) {
96 const char* val = getenv("ANDROID_ADDITIONAL_PUBLIC_LIBRARIES");
97 return val ? val : "";
98 }
99 return "";
100}
101
Jooyung Han26f7d102020-02-22 23:39:23 +0900102// insert vndk version in every {} placeholder
Justin Yun089c1352020-02-06 16:53:08 +0900103void InsertVndkVersionStr(std::string* file_name, bool use_product_vndk) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100104 CHECK(file_name != nullptr);
Jooyung Han26f7d102020-02-22 23:39:23 +0900105 auto version = vndk_version_str(use_product_vndk);
106 size_t pos = file_name->find("{}");
107 while (pos != std::string::npos) {
108 file_name->replace(pos, 2, version);
109 pos = file_name->find("{}", pos + version.size());
Orion Hodson9b16e342019-10-09 13:29:16 +0100110 }
Orion Hodson9b16e342019-10-09 13:29:16 +0100111}
112
113const std::function<Result<bool>(const struct ConfigEntry&)> always_true =
114 [](const struct ConfigEntry&) -> Result<bool> { return true; };
115
116Result<std::vector<std::string>> ReadConfig(
117 const std::string& configFile,
118 const std::function<Result<bool>(const ConfigEntry& /* entry */)>& filter_fn) {
119 std::string file_content;
120 if (!base::ReadFileToString(configFile, &file_content)) {
121 return ErrnoError();
122 }
123 Result<std::vector<std::string>> result = ParseConfig(file_content, filter_fn);
Bernie Innocenti4bd58952020-02-06 15:43:57 +0900124 if (!result.ok()) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100125 return Errorf("Cannot parse {}: {}", configFile, result.error().message());
126 }
127 return result;
128}
129
130void ReadExtensionLibraries(const char* dirname, std::vector<std::string>* sonames) {
131 std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(dirname), closedir);
132 if (dir != nullptr) {
133 // Failing to opening the dir is not an error, which can happen in
134 // webview_zygote.
135 while (struct dirent* ent = readdir(dir.get())) {
136 if (ent->d_type != DT_REG && ent->d_type != DT_LNK) {
137 continue;
138 }
139 const std::string filename(ent->d_name);
140 std::string_view fn = filename;
141 if (android::base::ConsumePrefix(&fn, kExtendedPublicLibrariesFilePrefix) &&
142 android::base::ConsumeSuffix(&fn, kExtendedPublicLibrariesFileSuffix)) {
143 const std::string company_name(fn);
144 const std::string config_file_path = dirname + "/"s + filename;
145 LOG_ALWAYS_FATAL_IF(
146 company_name.empty(),
147 "Error extracting company name from public native library list file path \"%s\"",
148 config_file_path.c_str());
149
150 auto ret = ReadConfig(
151 config_file_path, [&company_name](const struct ConfigEntry& entry) -> Result<bool> {
152 if (android::base::StartsWith(entry.soname, "lib") &&
153 android::base::EndsWith(entry.soname, "." + company_name + ".so")) {
154 return true;
155 } else {
156 return Errorf("Library name \"{}\" does not end with the company name {}.",
157 entry.soname, company_name);
158 }
159 });
Bernie Innocenti4bd58952020-02-06 15:43:57 +0900160 if (ret.ok()) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100161 sonames->insert(sonames->end(), ret->begin(), ret->end());
162 } else {
163 LOG_ALWAYS_FATAL("Error reading public native library list from \"%s\": %s",
164 config_file_path.c_str(), ret.error().message().c_str());
165 }
166 }
167 }
168 }
169}
170
171static std::string InitDefaultPublicLibraries(bool for_preload) {
172 std::string config_file = root_dir() + kDefaultPublicLibrariesFile;
173 auto sonames =
174 ReadConfig(config_file, [&for_preload](const struct ConfigEntry& entry) -> Result<bool> {
175 if (for_preload) {
176 return !entry.nopreload;
177 } else {
178 return true;
179 }
180 });
Bernie Innocenti4bd58952020-02-06 15:43:57 +0900181 if (!sonames.ok()) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100182 LOG_ALWAYS_FATAL("Error reading public native library list from \"%s\": %s",
183 config_file.c_str(), sonames.error().message().c_str());
184 return "";
185 }
186
187 std::string additional_libs = additional_public_libraries();
188 if (!additional_libs.empty()) {
189 auto vec = base::Split(additional_libs, ":");
190 std::copy(vec.begin(), vec.end(), std::back_inserter(*sonames));
191 }
192
193 // If this is for preloading libs, don't remove the libs from APEXes.
194 if (for_preload) {
195 return android::base::Join(*sonames, ':');
196 }
197
vichang4a487752020-05-05 11:11:30 +0000198 // Remove the public libs in the art namespace.
Orion Hodson9b16e342019-10-09 13:29:16 +0100199 // These libs are listed in public.android.txt, but we don't want the rest of android
200 // in default namespace to dlopen the libs.
201 // For example, libicuuc.so is exposed to classloader namespace from art namespace.
202 // Unfortunately, it does not have stable C symbols, and default namespace should only use
203 // stable symbols in libandroidicu.so. http://b/120786417
vichang4a487752020-05-05 11:11:30 +0000204 for (const std::string& lib_name : kArtApexPublicLibraries) {
205 std::string path(kArtApexLibPath);
Orion Hodson9b16e342019-10-09 13:29:16 +0100206 path.append("/").append(lib_name);
207
208 struct stat s;
209 // Do nothing if the path in /apex does not exist.
210 // Runtime APEX must be mounted since libnativeloader is in the same APEX
211 if (stat(path.c_str(), &s) != 0) {
212 continue;
213 }
214
215 auto it = std::find(sonames->begin(), sonames->end(), lib_name);
216 if (it != sonames->end()) {
217 sonames->erase(it);
218 }
219 }
220
221 // Remove the public libs in the nnapi namespace.
222 auto it = std::find(sonames->begin(), sonames->end(), kNeuralNetworksApexPublicLibrary);
223 if (it != sonames->end()) {
224 sonames->erase(it);
225 }
226 return android::base::Join(*sonames, ':');
227}
228
229static std::string InitArtPublicLibraries() {
Chris Wailes72d7e962020-04-15 09:37:38 -0700230 CHECK_GT((int)kArtApexPublicLibraries.size(), 0);
Orion Hodson9b16e342019-10-09 13:29:16 +0100231 std::string list = android::base::Join(kArtApexPublicLibraries, ":");
232
233 std::string additional_libs = additional_public_libraries();
234 if (!additional_libs.empty()) {
235 list = list + ':' + additional_libs;
236 }
237 return list;
238}
239
240static std::string InitVendorPublicLibraries() {
241 // This file is optional, quietly ignore if the file does not exist.
242 auto sonames = ReadConfig(kVendorPublicLibrariesFile, always_true);
Bernie Innocenti4bd58952020-02-06 15:43:57 +0900243 if (!sonames.ok()) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100244 return "";
245 }
246 return android::base::Join(*sonames, ':');
247}
248
Justin Yun0cc40272019-12-16 16:47:40 +0900249// read /system/etc/public.libraries-<companyname>.txt,
250// /system_ext/etc/public.libraries-<companyname>.txt and
Orion Hodson9b16e342019-10-09 13:29:16 +0100251// /product/etc/public.libraries-<companyname>.txt which contain partner defined
252// system libs that are exposed to apps. The libs in the txt files must be
253// named as lib<name>.<companyname>.so.
254static std::string InitExtendedPublicLibraries() {
255 std::vector<std::string> sonames;
256 ReadExtensionLibraries("/system/etc", &sonames);
Justin Yun0cc40272019-12-16 16:47:40 +0900257 ReadExtensionLibraries("/system_ext/etc", &sonames);
Orion Hodson9b16e342019-10-09 13:29:16 +0100258 ReadExtensionLibraries("/product/etc", &sonames);
259 return android::base::Join(sonames, ':');
260}
261
Justin Yun089c1352020-02-06 16:53:08 +0900262static std::string InitLlndkLibrariesVendor() {
Orion Hodson9b16e342019-10-09 13:29:16 +0100263 std::string config_file = kLlndkLibrariesFile;
Justin Yun089c1352020-02-06 16:53:08 +0900264 InsertVndkVersionStr(&config_file, false);
265 auto sonames = ReadConfig(config_file, always_true);
Bernie Innocentic1375632020-02-13 10:37:03 +0900266 if (!sonames.ok()) {
Jooyung Han26f7d102020-02-22 23:39:23 +0900267 LOG_ALWAYS_FATAL("%s: %s", config_file.c_str(), sonames.error().message().c_str());
Justin Yun089c1352020-02-06 16:53:08 +0900268 return "";
269 }
270 return android::base::Join(*sonames, ':');
271}
272
273static std::string InitLlndkLibrariesProduct() {
Justin Yun696882f2020-03-24 13:31:19 +0900274 if (!is_product_vndk_version_defined()) {
275 return "";
276 }
Justin Yun089c1352020-02-06 16:53:08 +0900277 std::string config_file = kLlndkLibrariesFile;
278 InsertVndkVersionStr(&config_file, true);
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()) {
Jooyung Han26f7d102020-02-22 23:39:23 +0900281 LOG_ALWAYS_FATAL("%s: %s", config_file.c_str(), sonames.error().message().c_str());
Orion Hodson9b16e342019-10-09 13:29:16 +0100282 return "";
283 }
284 return android::base::Join(*sonames, ':');
285}
286
Justin Yuneb4f08c2020-02-18 11:29:07 +0900287static std::string InitVndkspLibrariesVendor() {
Orion Hodson9b16e342019-10-09 13:29:16 +0100288 std::string config_file = kVndkLibrariesFile;
Justin Yun089c1352020-02-06 16:53:08 +0900289 InsertVndkVersionStr(&config_file, false);
Orion Hodson9b16e342019-10-09 13:29:16 +0100290 auto sonames = ReadConfig(config_file, always_true);
Bernie Innocenti4bd58952020-02-06 15:43:57 +0900291 if (!sonames.ok()) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100292 LOG_ALWAYS_FATAL("%s", sonames.error().message().c_str());
293 return "";
294 }
295 return android::base::Join(*sonames, ':');
296}
297
Justin Yuneb4f08c2020-02-18 11:29:07 +0900298static std::string InitVndkspLibrariesProduct() {
Justin Yun696882f2020-03-24 13:31:19 +0900299 if (!is_product_vndk_version_defined()) {
300 return "";
301 }
Justin Yuneb4f08c2020-02-18 11:29:07 +0900302 std::string config_file = kVndkLibrariesFile;
303 InsertVndkVersionStr(&config_file, true);
304 auto sonames = ReadConfig(config_file, always_true);
305 if (!sonames.ok()) {
306 LOG_ALWAYS_FATAL("%s", sonames.error().message().c_str());
307 return "";
308 }
309 return android::base::Join(*sonames, ':');
310}
311
Orion Hodson9b16e342019-10-09 13:29:16 +0100312static std::string InitNeuralNetworksPublicLibraries() {
313 return kNeuralNetworksApexPublicLibrary;
314}
315
Jeffrey Huang52575032020-02-11 17:33:45 -0800316static std::string InitStatsdPublicLibraries() {
317 return kStatsdApexPublicLibrary;
318}
319
Jooyung Han538f99a2020-03-03 00:46:50 +0900320static std::map<std::string, std::string> InitApexJniLibraries() {
321 std::string file_content;
322 if (!base::ReadFileToString(kJniConfigFile, &file_content)) {
323 // jni config is optional
324 return {};
325 }
326 auto config = ParseJniConfig(file_content);
327 if (!config.ok()) {
328 LOG_ALWAYS_FATAL("%s: %s", kJniConfigFile, config.error().message().c_str());
329 // not reach here
330 return {};
331 }
332 return *config;
333}
334
Orion Hodson9b16e342019-10-09 13:29:16 +0100335} // namespace
336
337const std::string& preloadable_public_libraries() {
338 static std::string list = InitDefaultPublicLibraries(/*for_preload*/ true);
339 return list;
340}
341
342const std::string& default_public_libraries() {
343 static std::string list = InitDefaultPublicLibraries(/*for_preload*/ false);
344 return list;
345}
346
347const std::string& art_public_libraries() {
348 static std::string list = InitArtPublicLibraries();
349 return list;
350}
351
352const std::string& vendor_public_libraries() {
353 static std::string list = InitVendorPublicLibraries();
354 return list;
355}
356
357const std::string& extended_public_libraries() {
358 static std::string list = InitExtendedPublicLibraries();
359 return list;
360}
361
362const std::string& neuralnetworks_public_libraries() {
363 static std::string list = InitNeuralNetworksPublicLibraries();
364 return list;
365}
366
Jeffrey Huang52575032020-02-11 17:33:45 -0800367const std::string& statsd_public_libraries() {
368 static std::string list = InitStatsdPublicLibraries();
369 return list;
370}
371
Justin Yun089c1352020-02-06 16:53:08 +0900372const std::string& llndk_libraries_product() {
373 static std::string list = InitLlndkLibrariesProduct();
374 return list;
375}
376
377const std::string& llndk_libraries_vendor() {
378 static std::string list = InitLlndkLibrariesVendor();
Orion Hodson9b16e342019-10-09 13:29:16 +0100379 return list;
380}
381
Justin Yuneb4f08c2020-02-18 11:29:07 +0900382const std::string& vndksp_libraries_product() {
383 static std::string list = InitVndkspLibrariesProduct();
384 return list;
385}
386
387const std::string& vndksp_libraries_vendor() {
388 static std::string list = InitVndkspLibrariesVendor();
Orion Hodson9b16e342019-10-09 13:29:16 +0100389 return list;
390}
391
Jooyung Han538f99a2020-03-03 00:46:50 +0900392const std::string& apex_jni_libraries(const std::string& apex_ns_name) {
393 static std::map<std::string, std::string> jni_libraries = InitApexJniLibraries();
394 return jni_libraries[apex_ns_name];
395}
396
Justin Yun3db26d52019-12-16 14:09:39 +0900397bool is_product_vndk_version_defined() {
Nicolas Geoffray7ca8b672020-04-24 15:43:48 +0100398#if defined(ART_TARGET_ANDROID)
Justin Yun3db26d52019-12-16 14:09:39 +0900399 return android::sysprop::VndkProperties::product_vndk_version().has_value();
400#else
401 return false;
402#endif
403}
404
Justin Yun089c1352020-02-06 16:53:08 +0900405std::string get_vndk_version(bool is_product_vndk) {
Nicolas Geoffray7ca8b672020-04-24 15:43:48 +0100406#if defined(ART_TARGET_ANDROID)
Justin Yun089c1352020-02-06 16:53:08 +0900407 if (is_product_vndk) {
408 return android::sysprop::VndkProperties::product_vndk_version().value_or("");
409 }
410 return android::sysprop::VndkProperties::vendor_vndk_version().value_or("");
411#else
412 if (is_product_vndk) {
413 return android::base::GetProperty("ro.product.vndk.version", "");
414 }
415 return android::base::GetProperty("ro.vndk.version", "");
416#endif
417}
418
Orion Hodson9b16e342019-10-09 13:29:16 +0100419namespace internal {
420// Exported for testing
421Result<std::vector<std::string>> ParseConfig(
422 const std::string& file_content,
423 const std::function<Result<bool>(const ConfigEntry& /* entry */)>& filter_fn) {
424 std::vector<std::string> lines = base::Split(file_content, "\n");
425
426 std::vector<std::string> sonames;
427 for (auto& line : lines) {
428 auto trimmed_line = base::Trim(line);
429 if (trimmed_line[0] == '#' || trimmed_line.empty()) {
430 continue;
431 }
432
433 std::vector<std::string> tokens = android::base::Split(trimmed_line, " ");
434 if (tokens.size() < 1 || tokens.size() > 3) {
435 return Errorf("Malformed line \"{}\"", line);
436 }
437 struct ConfigEntry entry = {.soname = "", .nopreload = false, .bitness = ALL};
438 size_t i = tokens.size();
439 while (i-- > 0) {
440 if (tokens[i] == "nopreload") {
441 entry.nopreload = true;
442 } else if (tokens[i] == "32" || tokens[i] == "64") {
443 if (entry.bitness != ALL) {
444 return Errorf("Malformed line \"{}\": bitness can be specified only once", line);
445 }
446 entry.bitness = tokens[i] == "32" ? ONLY_32 : ONLY_64;
447 } else {
448 if (i != 0) {
449 return Errorf("Malformed line \"{}\"", line);
450 }
451 entry.soname = tokens[i];
452 }
453 }
454
455 // skip 32-bit lib on 64-bit process and vice versa
456#if defined(__LP64__)
457 if (entry.bitness == ONLY_32) continue;
458#else
459 if (entry.bitness == ONLY_64) continue;
460#endif
461
462 Result<bool> ret = filter_fn(entry);
Bernie Innocenti4bd58952020-02-06 15:43:57 +0900463 if (!ret.ok()) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100464 return ret.error();
465 }
466 if (*ret) {
467 // filter_fn has returned true.
468 sonames.push_back(entry.soname);
469 }
470 }
471 return sonames;
472}
473
Jooyung Han538f99a2020-03-03 00:46:50 +0900474Result<std::map<std::string, std::string>> ParseJniConfig(const std::string& file_content) {
475 std::map<std::string, std::string> entries;
476 std::vector<std::string> lines = base::Split(file_content, "\n");
477 for (auto& line : lines) {
478 auto trimmed_line = base::Trim(line);
479 if (trimmed_line[0] == '#' || trimmed_line.empty()) {
480 continue;
481 }
482
483 std::vector<std::string> tokens = base::Split(trimmed_line, " ");
484 if (tokens.size() < 2) {
485 return Errorf( "Malformed line \"{}\"", line);
486 }
487 entries[tokens[0]] = tokens[1];
488 }
489 return entries;
490}
491
Orion Hodson9b16e342019-10-09 13:29:16 +0100492} // namespace internal
493
494} // namespace android::nativeloader