blob: 258dbf69f0bff3a727d1f50f906790b600d8bdc7 [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
Justin Yun3db26d52019-12-16 14:09:39 +090034#if defined(__ANDROID__)
35#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 = {
60 "libicuuc.so",
61 "libicui18n.so",
62};
63
64constexpr const char* kArtApexLibPath = "/apex/com.android.art/" LIB;
65
66constexpr const char* kNeuralNetworksApexPublicLibrary = "libneuralnetworks.so";
67
Jeffrey Huang52575032020-02-11 17:33:45 -080068constexpr const char* kStatsdApexPublicLibrary = "libstats_jni.so";
69
Orion Hodson9b16e342019-10-09 13:29:16 +010070// TODO(b/130388701): do we need this?
71std::string root_dir() {
72 static const char* android_root_env = getenv("ANDROID_ROOT");
73 return android_root_env != nullptr ? android_root_env : "/system";
74}
75
76bool debuggable() {
77 static bool debuggable = android::base::GetBoolProperty("ro.debuggable", false);
78 return debuggable;
79}
80
Justin Yun089c1352020-02-06 16:53:08 +090081std::string vndk_version_str(bool use_product_vndk) {
Jooyung Han26f7d102020-02-22 23:39:23 +090082 if (use_product_vndk) {
83 static std::string product_vndk_version = get_vndk_version(true);
84 return product_vndk_version;
85 } else {
86 static std::string vendor_vndk_version = get_vndk_version(false);
87 return vendor_vndk_version;
Orion Hodson9b16e342019-10-09 13:29:16 +010088 }
Orion Hodson9b16e342019-10-09 13:29:16 +010089}
90
91// For debuggable platform builds use ANDROID_ADDITIONAL_PUBLIC_LIBRARIES environment
92// variable to add libraries to the list. This is intended for platform tests only.
93std::string additional_public_libraries() {
94 if (debuggable()) {
95 const char* val = getenv("ANDROID_ADDITIONAL_PUBLIC_LIBRARIES");
96 return val ? val : "";
97 }
98 return "";
99}
100
Jooyung Han26f7d102020-02-22 23:39:23 +0900101// insert vndk version in every {} placeholder
Justin Yun089c1352020-02-06 16:53:08 +0900102void InsertVndkVersionStr(std::string* file_name, bool use_product_vndk) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100103 CHECK(file_name != nullptr);
Jooyung Han26f7d102020-02-22 23:39:23 +0900104 auto version = vndk_version_str(use_product_vndk);
105 size_t pos = file_name->find("{}");
106 while (pos != std::string::npos) {
107 file_name->replace(pos, 2, version);
108 pos = file_name->find("{}", pos + version.size());
Orion Hodson9b16e342019-10-09 13:29:16 +0100109 }
Orion Hodson9b16e342019-10-09 13:29:16 +0100110}
111
112const std::function<Result<bool>(const struct ConfigEntry&)> always_true =
113 [](const struct ConfigEntry&) -> Result<bool> { return true; };
114
115Result<std::vector<std::string>> ReadConfig(
116 const std::string& configFile,
117 const std::function<Result<bool>(const ConfigEntry& /* entry */)>& filter_fn) {
118 std::string file_content;
119 if (!base::ReadFileToString(configFile, &file_content)) {
120 return ErrnoError();
121 }
122 Result<std::vector<std::string>> result = ParseConfig(file_content, filter_fn);
Bernie Innocenti4bd58952020-02-06 15:43:57 +0900123 if (!result.ok()) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100124 return Errorf("Cannot parse {}: {}", configFile, result.error().message());
125 }
126 return result;
127}
128
129void ReadExtensionLibraries(const char* dirname, std::vector<std::string>* sonames) {
130 std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(dirname), closedir);
131 if (dir != nullptr) {
132 // Failing to opening the dir is not an error, which can happen in
133 // webview_zygote.
134 while (struct dirent* ent = readdir(dir.get())) {
135 if (ent->d_type != DT_REG && ent->d_type != DT_LNK) {
136 continue;
137 }
138 const std::string filename(ent->d_name);
139 std::string_view fn = filename;
140 if (android::base::ConsumePrefix(&fn, kExtendedPublicLibrariesFilePrefix) &&
141 android::base::ConsumeSuffix(&fn, kExtendedPublicLibrariesFileSuffix)) {
142 const std::string company_name(fn);
143 const std::string config_file_path = dirname + "/"s + filename;
144 LOG_ALWAYS_FATAL_IF(
145 company_name.empty(),
146 "Error extracting company name from public native library list file path \"%s\"",
147 config_file_path.c_str());
148
149 auto ret = ReadConfig(
150 config_file_path, [&company_name](const struct ConfigEntry& entry) -> Result<bool> {
151 if (android::base::StartsWith(entry.soname, "lib") &&
152 android::base::EndsWith(entry.soname, "." + company_name + ".so")) {
153 return true;
154 } else {
155 return Errorf("Library name \"{}\" does not end with the company name {}.",
156 entry.soname, company_name);
157 }
158 });
Bernie Innocenti4bd58952020-02-06 15:43:57 +0900159 if (ret.ok()) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100160 sonames->insert(sonames->end(), ret->begin(), ret->end());
161 } else {
162 LOG_ALWAYS_FATAL("Error reading public native library list from \"%s\": %s",
163 config_file_path.c_str(), ret.error().message().c_str());
164 }
165 }
166 }
167 }
168}
169
170static std::string InitDefaultPublicLibraries(bool for_preload) {
171 std::string config_file = root_dir() + kDefaultPublicLibrariesFile;
172 auto sonames =
173 ReadConfig(config_file, [&for_preload](const struct ConfigEntry& entry) -> Result<bool> {
174 if (for_preload) {
175 return !entry.nopreload;
176 } else {
177 return true;
178 }
179 });
Bernie Innocenti4bd58952020-02-06 15:43:57 +0900180 if (!sonames.ok()) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100181 LOG_ALWAYS_FATAL("Error reading public native library list from \"%s\": %s",
182 config_file.c_str(), sonames.error().message().c_str());
183 return "";
184 }
185
186 std::string additional_libs = additional_public_libraries();
187 if (!additional_libs.empty()) {
188 auto vec = base::Split(additional_libs, ":");
189 std::copy(vec.begin(), vec.end(), std::back_inserter(*sonames));
190 }
191
192 // If this is for preloading libs, don't remove the libs from APEXes.
193 if (for_preload) {
194 return android::base::Join(*sonames, ':');
195 }
196
197 // Remove the public libs in the art namespace.
198 // These libs are listed in public.android.txt, but we don't want the rest of android
199 // in default namespace to dlopen the libs.
200 // For example, libicuuc.so is exposed to classloader namespace from art namespace.
201 // Unfortunately, it does not have stable C symbols, and default namespace should only use
202 // stable symbols in libandroidicu.so. http://b/120786417
203 for (const std::string& lib_name : kArtApexPublicLibraries) {
204 std::string path(kArtApexLibPath);
205 path.append("/").append(lib_name);
206
207 struct stat s;
208 // Do nothing if the path in /apex does not exist.
209 // Runtime APEX must be mounted since libnativeloader is in the same APEX
210 if (stat(path.c_str(), &s) != 0) {
211 continue;
212 }
213
214 auto it = std::find(sonames->begin(), sonames->end(), lib_name);
215 if (it != sonames->end()) {
216 sonames->erase(it);
217 }
218 }
219
220 // Remove the public libs in the nnapi namespace.
221 auto it = std::find(sonames->begin(), sonames->end(), kNeuralNetworksApexPublicLibrary);
222 if (it != sonames->end()) {
223 sonames->erase(it);
224 }
225 return android::base::Join(*sonames, ':');
226}
227
228static std::string InitArtPublicLibraries() {
Chris Wailes72d7e962020-04-15 09:37:38 -0700229 CHECK_GT((int)kArtApexPublicLibraries.size(), 0);
Orion Hodson9b16e342019-10-09 13:29:16 +0100230 std::string list = android::base::Join(kArtApexPublicLibraries, ":");
231
232 std::string additional_libs = additional_public_libraries();
233 if (!additional_libs.empty()) {
234 list = list + ':' + additional_libs;
235 }
236 return list;
237}
238
239static std::string InitVendorPublicLibraries() {
240 // This file is optional, quietly ignore if the file does not exist.
241 auto sonames = ReadConfig(kVendorPublicLibrariesFile, always_true);
Bernie Innocenti4bd58952020-02-06 15:43:57 +0900242 if (!sonames.ok()) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100243 return "";
244 }
245 return android::base::Join(*sonames, ':');
246}
247
Justin Yun0cc40272019-12-16 16:47:40 +0900248// read /system/etc/public.libraries-<companyname>.txt,
249// /system_ext/etc/public.libraries-<companyname>.txt and
Orion Hodson9b16e342019-10-09 13:29:16 +0100250// /product/etc/public.libraries-<companyname>.txt which contain partner defined
251// system libs that are exposed to apps. The libs in the txt files must be
252// named as lib<name>.<companyname>.so.
253static std::string InitExtendedPublicLibraries() {
254 std::vector<std::string> sonames;
255 ReadExtensionLibraries("/system/etc", &sonames);
Justin Yun0cc40272019-12-16 16:47:40 +0900256 ReadExtensionLibraries("/system_ext/etc", &sonames);
Orion Hodson9b16e342019-10-09 13:29:16 +0100257 ReadExtensionLibraries("/product/etc", &sonames);
258 return android::base::Join(sonames, ':');
259}
260
Justin Yun089c1352020-02-06 16:53:08 +0900261static std::string InitLlndkLibrariesVendor() {
Orion Hodson9b16e342019-10-09 13:29:16 +0100262 std::string config_file = kLlndkLibrariesFile;
Justin Yun089c1352020-02-06 16:53:08 +0900263 InsertVndkVersionStr(&config_file, false);
264 auto sonames = ReadConfig(config_file, always_true);
Bernie Innocentic1375632020-02-13 10:37:03 +0900265 if (!sonames.ok()) {
Jooyung Han26f7d102020-02-22 23:39:23 +0900266 LOG_ALWAYS_FATAL("%s: %s", config_file.c_str(), sonames.error().message().c_str());
Justin Yun089c1352020-02-06 16:53:08 +0900267 return "";
268 }
269 return android::base::Join(*sonames, ':');
270}
271
272static std::string InitLlndkLibrariesProduct() {
Justin Yun696882f2020-03-24 13:31:19 +0900273 if (!is_product_vndk_version_defined()) {
274 return "";
275 }
Justin Yun089c1352020-02-06 16:53:08 +0900276 std::string config_file = kLlndkLibrariesFile;
277 InsertVndkVersionStr(&config_file, true);
Orion Hodson9b16e342019-10-09 13:29:16 +0100278 auto sonames = ReadConfig(config_file, always_true);
Bernie Innocenti4bd58952020-02-06 15:43:57 +0900279 if (!sonames.ok()) {
Jooyung Han26f7d102020-02-22 23:39:23 +0900280 LOG_ALWAYS_FATAL("%s: %s", config_file.c_str(), sonames.error().message().c_str());
Orion Hodson9b16e342019-10-09 13:29:16 +0100281 return "";
282 }
283 return android::base::Join(*sonames, ':');
284}
285
Justin Yuneb4f08c2020-02-18 11:29:07 +0900286static std::string InitVndkspLibrariesVendor() {
Orion Hodson9b16e342019-10-09 13:29:16 +0100287 std::string config_file = kVndkLibrariesFile;
Justin Yun089c1352020-02-06 16:53:08 +0900288 InsertVndkVersionStr(&config_file, false);
Orion Hodson9b16e342019-10-09 13:29:16 +0100289 auto sonames = ReadConfig(config_file, always_true);
Bernie Innocenti4bd58952020-02-06 15:43:57 +0900290 if (!sonames.ok()) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100291 LOG_ALWAYS_FATAL("%s", sonames.error().message().c_str());
292 return "";
293 }
294 return android::base::Join(*sonames, ':');
295}
296
Justin Yuneb4f08c2020-02-18 11:29:07 +0900297static std::string InitVndkspLibrariesProduct() {
Justin Yun696882f2020-03-24 13:31:19 +0900298 if (!is_product_vndk_version_defined()) {
299 return "";
300 }
Justin Yuneb4f08c2020-02-18 11:29:07 +0900301 std::string config_file = kVndkLibrariesFile;
302 InsertVndkVersionStr(&config_file, true);
303 auto sonames = ReadConfig(config_file, always_true);
304 if (!sonames.ok()) {
305 LOG_ALWAYS_FATAL("%s", sonames.error().message().c_str());
306 return "";
307 }
308 return android::base::Join(*sonames, ':');
309}
310
Orion Hodson9b16e342019-10-09 13:29:16 +0100311static std::string InitNeuralNetworksPublicLibraries() {
312 return kNeuralNetworksApexPublicLibrary;
313}
314
Jeffrey Huang52575032020-02-11 17:33:45 -0800315static std::string InitStatsdPublicLibraries() {
316 return kStatsdApexPublicLibrary;
317}
318
Jooyung Han538f99a2020-03-03 00:46:50 +0900319static std::map<std::string, std::string> InitApexJniLibraries() {
320 std::string file_content;
321 if (!base::ReadFileToString(kJniConfigFile, &file_content)) {
322 // jni config is optional
323 return {};
324 }
325 auto config = ParseJniConfig(file_content);
326 if (!config.ok()) {
327 LOG_ALWAYS_FATAL("%s: %s", kJniConfigFile, config.error().message().c_str());
328 // not reach here
329 return {};
330 }
331 return *config;
332}
333
Orion Hodson9b16e342019-10-09 13:29:16 +0100334} // namespace
335
336const std::string& preloadable_public_libraries() {
337 static std::string list = InitDefaultPublicLibraries(/*for_preload*/ true);
338 return list;
339}
340
341const std::string& default_public_libraries() {
342 static std::string list = InitDefaultPublicLibraries(/*for_preload*/ false);
343 return list;
344}
345
346const std::string& art_public_libraries() {
347 static std::string list = InitArtPublicLibraries();
348 return list;
349}
350
351const std::string& vendor_public_libraries() {
352 static std::string list = InitVendorPublicLibraries();
353 return list;
354}
355
356const std::string& extended_public_libraries() {
357 static std::string list = InitExtendedPublicLibraries();
358 return list;
359}
360
361const std::string& neuralnetworks_public_libraries() {
362 static std::string list = InitNeuralNetworksPublicLibraries();
363 return list;
364}
365
Jeffrey Huang52575032020-02-11 17:33:45 -0800366const std::string& statsd_public_libraries() {
367 static std::string list = InitStatsdPublicLibraries();
368 return list;
369}
370
Justin Yun089c1352020-02-06 16:53:08 +0900371const std::string& llndk_libraries_product() {
372 static std::string list = InitLlndkLibrariesProduct();
373 return list;
374}
375
376const std::string& llndk_libraries_vendor() {
377 static std::string list = InitLlndkLibrariesVendor();
Orion Hodson9b16e342019-10-09 13:29:16 +0100378 return list;
379}
380
Justin Yuneb4f08c2020-02-18 11:29:07 +0900381const std::string& vndksp_libraries_product() {
382 static std::string list = InitVndkspLibrariesProduct();
383 return list;
384}
385
386const std::string& vndksp_libraries_vendor() {
387 static std::string list = InitVndkspLibrariesVendor();
Orion Hodson9b16e342019-10-09 13:29:16 +0100388 return list;
389}
390
Jooyung Han538f99a2020-03-03 00:46:50 +0900391const std::string& apex_jni_libraries(const std::string& apex_ns_name) {
392 static std::map<std::string, std::string> jni_libraries = InitApexJniLibraries();
393 return jni_libraries[apex_ns_name];
394}
395
Justin Yun3db26d52019-12-16 14:09:39 +0900396bool is_product_vndk_version_defined() {
397#if defined(__ANDROID__)
398 return android::sysprop::VndkProperties::product_vndk_version().has_value();
399#else
400 return false;
401#endif
402}
403
Justin Yun089c1352020-02-06 16:53:08 +0900404std::string get_vndk_version(bool is_product_vndk) {
405#if defined(__ANDROID__)
406 if (is_product_vndk) {
407 return android::sysprop::VndkProperties::product_vndk_version().value_or("");
408 }
409 return android::sysprop::VndkProperties::vendor_vndk_version().value_or("");
410#else
411 if (is_product_vndk) {
412 return android::base::GetProperty("ro.product.vndk.version", "");
413 }
414 return android::base::GetProperty("ro.vndk.version", "");
415#endif
416}
417
Orion Hodson9b16e342019-10-09 13:29:16 +0100418namespace internal {
419// Exported for testing
420Result<std::vector<std::string>> ParseConfig(
421 const std::string& file_content,
422 const std::function<Result<bool>(const ConfigEntry& /* entry */)>& filter_fn) {
423 std::vector<std::string> lines = base::Split(file_content, "\n");
424
425 std::vector<std::string> sonames;
426 for (auto& line : lines) {
427 auto trimmed_line = base::Trim(line);
428 if (trimmed_line[0] == '#' || trimmed_line.empty()) {
429 continue;
430 }
431
432 std::vector<std::string> tokens = android::base::Split(trimmed_line, " ");
433 if (tokens.size() < 1 || tokens.size() > 3) {
434 return Errorf("Malformed line \"{}\"", line);
435 }
436 struct ConfigEntry entry = {.soname = "", .nopreload = false, .bitness = ALL};
437 size_t i = tokens.size();
438 while (i-- > 0) {
439 if (tokens[i] == "nopreload") {
440 entry.nopreload = true;
441 } else if (tokens[i] == "32" || tokens[i] == "64") {
442 if (entry.bitness != ALL) {
443 return Errorf("Malformed line \"{}\": bitness can be specified only once", line);
444 }
445 entry.bitness = tokens[i] == "32" ? ONLY_32 : ONLY_64;
446 } else {
447 if (i != 0) {
448 return Errorf("Malformed line \"{}\"", line);
449 }
450 entry.soname = tokens[i];
451 }
452 }
453
454 // skip 32-bit lib on 64-bit process and vice versa
455#if defined(__LP64__)
456 if (entry.bitness == ONLY_32) continue;
457#else
458 if (entry.bitness == ONLY_64) continue;
459#endif
460
461 Result<bool> ret = filter_fn(entry);
Bernie Innocenti4bd58952020-02-06 15:43:57 +0900462 if (!ret.ok()) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100463 return ret.error();
464 }
465 if (*ret) {
466 // filter_fn has returned true.
467 sonames.push_back(entry.soname);
468 }
469 }
470 return sonames;
471}
472
Jooyung Han538f99a2020-03-03 00:46:50 +0900473Result<std::map<std::string, std::string>> ParseJniConfig(const std::string& file_content) {
474 std::map<std::string, std::string> entries;
475 std::vector<std::string> lines = base::Split(file_content, "\n");
476 for (auto& line : lines) {
477 auto trimmed_line = base::Trim(line);
478 if (trimmed_line[0] == '#' || trimmed_line.empty()) {
479 continue;
480 }
481
482 std::vector<std::string> tokens = base::Split(trimmed_line, " ");
483 if (tokens.size() < 2) {
484 return Errorf( "Malformed line \"{}\"", line);
485 }
486 entries[tokens[0]] = tokens[1];
487 }
488 return entries;
489}
490
Orion Hodson9b16e342019-10-09 13:29:16 +0100491} // namespace internal
492
493} // namespace android::nativeloader