From 52ccfa77b746bc4b59787dcff015c15ab630934a Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Tue, 1 Sep 2020 13:49:27 +0900 Subject: [PATCH] make APEXes with public libraries visible Public libraries (listed in /system/etc/public.libraries.txt) should be available to classloader-namespace (created by libnativeloader). So, linkerconfig reads public.libraries.txt and makes apexes with public libraries visible. This cleans up hard-coded references to nn, i18n, art apexes. And the list of apexes along with public libs are stored in /linkerconfig/apex.libraries.config.txt so that libnativeloader can read it and link them to classloader-namespace. Bug: 150767721 Test: cuttlefish boots Test: atest --host linkerconfig_diff_test Change-Id: Idd7e2b0bcc6e54cd79c2b9c4c755f883b4507b74 --- README.md | 42 ++++++++++----- contents/section/apexart.cc | 23 +++++---- contents/section/isolated.cc | 7 +-- contents/section/legacy.cc | 7 +-- contents/section/product.cc | 20 +++++--- contents/section/sectionbuilder.cc | 14 ++++- contents/section/system.cc | 7 +-- contents/section/unrestricted.cc | 7 +-- contents/section/vendor.cc | 20 +++++--- main.cc | 14 +++-- modules/apex.cc | 59 +++++++++++++++++++++- modules/include/linkerconfig/apex.h | 1 + .../golden_output/legacy/apex.libraries.config.txt | 4 ++ testdata/golden_output/legacy/jni.config.txt | 1 - .../product-enabled/apex.libraries.config.txt | 4 ++ .../golden_output/product-enabled/jni.config.txt | 1 - .../golden_output/product-enabled/ld.config.txt | 2 + .../{jni.config.txt => apex.libraries.config.txt} | 0 .../golden_output/stage1/apex.libraries.config.txt | 2 + testdata/golden_output/stage1/jni.config.txt | 0 testdata/golden_output/stage1/ld.config.txt | 1 + .../golden_output/stage2/apex.libraries.config.txt | 4 ++ testdata/golden_output/stage2/jni.config.txt | 1 - testdata/golden_output/stage2/ld.config.txt | 1 + testdata/root/system/etc/public.libraries.txt | 29 +++++++++++ 25 files changed, 203 insertions(+), 68 deletions(-) create mode 100644 testdata/golden_output/legacy/apex.libraries.config.txt delete mode 100644 testdata/golden_output/legacy/jni.config.txt create mode 100644 testdata/golden_output/product-enabled/apex.libraries.config.txt delete mode 100644 testdata/golden_output/product-enabled/jni.config.txt rename testdata/golden_output/stage0/{jni.config.txt => apex.libraries.config.txt} (100%) create mode 100644 testdata/golden_output/stage1/apex.libraries.config.txt delete mode 100644 testdata/golden_output/stage1/jni.config.txt create mode 100644 testdata/golden_output/stage2/apex.libraries.config.txt delete mode 100644 testdata/golden_output/stage2/jni.config.txt create mode 100644 testdata/root/system/etc/public.libraries.txt diff --git a/README.md b/README.md index cf7aa0a..ade17c1 100644 --- a/README.md +++ b/README.md @@ -8,19 +8,16 @@ other files under /linkerconfig during init. Linker will read this generated configuration file(s) to find out link relationship between libraries and executable. -## File Formats +## Inputs -There are several file formats used by linkerconfig. +TODO: explain inputs (e.g. /system/etc/public.libraries.txt, /apex/apex-info-list.xml, ..) -### Input +### /apex/*/etc/linker.config.txt -#### APEX Linker configuration - -This document describes format of `linker.config.txt` file under APEX `etc` -directory. This file can be used to add extra information while linkerconfig +APEX linker configuration file can be used to add extra information while linkerconfig creates linker configuration with the APEX module. -##### Format +#### Format This configuration has multiple sections, which is defined with `[section_name]` and there are multiple properties for each section. Format of the property can @@ -28,13 +25,13 @@ be varied based on the section, but in usual it is list of items or assiging value to name with ` = ` format. Available sections are pre-defined as below. -###### Extra permitted path section +#### Extra permitted path section Extra permitted path section has section name as `permitted_paths`. This section contains property as a list of items, and each item is an extra permitted path which should be added in the APEX namespace. -##### Example +#### Example ``` # This is a example APEX linker configuration @@ -47,11 +44,30 @@ which should be added in the APEX namespace. # EOF ``` -## Output +## Outputs + +### /linkerconfig/ld.config.txt & /linkerconfig/*/ld.config.txt -### ld.config.txt +TODO: a few words about the files Check [ld.config.format.md](https://android.googlesource.com/platform/bionic/+/master/linker/ld.config.format.md). -### apex.libraries.txt +### /linkerconfig/apex.libraries.txt + +The file describes libraries exposed from APEXes. libnativeloader is the main consumer of this file. + +``` +# comment line +jni com_android_foo libfoo_jni.so +public com_android_bar libbar.so:libbaz.so +``` + +The file is line-based and each line consists of `tag apex_namespace library_list`. + +- `tag` explains what `library_list` is. +- `apex_namespace` is the namespace of the apex. Note that it is mangled like `com_android_foo` for the APEX("com.android.foo"). +- `library_list` is colon-separated list of library names. + - if `tag` is `jni`, `library_list` is the list of JNI libraries exposed by `apex_namespace`. + - if `tag` is `public`, `library_list` is the list of public libraries exposed by `apex_namespace`. + Here, public libraries are the libs listed in `/system/etc/public.libraries.txt.` \ No newline at end of file diff --git a/contents/section/apexart.cc b/contents/section/apexart.cc index 118ce48..897d7d9 100644 --- a/contents/section/apexart.cc +++ b/contents/section/apexart.cc @@ -36,16 +36,21 @@ Section BuildApexArtSection(Context& ctx, const ApexInfo& apex_info) { namespaces.emplace_back(BuildApexArtDefaultNamespace(ctx)); namespaces.emplace_back(BuildApexPlatformNamespace(ctx)); + namespaces.emplace_back(BuildArtNamespace(ctx, apex_info)); - return BuildSection(ctx, - apex_info.name, - std::move(namespaces), - { - "com.android.art", - "com.android.i18n", - "com.android.conscrypt", - "com.android.neuralnetworks", - }); + std::set visible_apexes{ + "com.android.conscrypt", + }; + + // APEXes with public libs should be visible + for (const auto& apex : ctx.GetApexModules()) { + if (apex.public_libs.size() > 0) { + visible_apexes.insert(apex.name); + } + } + + return BuildSection( + ctx, apex_info.name, std::move(namespaces), visible_apexes); } } // namespace contents } // namespace linkerconfig diff --git a/contents/section/isolated.cc b/contents/section/isolated.cc index d8c17fe..4fdb8b5 100644 --- a/contents/section/isolated.cc +++ b/contents/section/isolated.cc @@ -36,18 +36,15 @@ Section BuildIsolatedSection(Context& ctx) { namespaces.emplace_back(BuildSystemNamespace(ctx)); std::set visible_apexes{ - "com.android.art", - "com.android.i18n", - "com.android.neuralnetworks", "com.android.runtime", "com.android.media", "com.android.conscrypt", "com.android.os.statsd", }; - // APEXes with JNI libs should be visible + // APEXes with JNI libs or public libs should be visible for (const auto& apex : ctx.GetApexModules()) { - if (apex.jni_libs.size() > 0) { + if (apex.jni_libs.size() > 0 || apex.public_libs.size() > 0) { visible_apexes.insert(apex.name); } } diff --git a/contents/section/legacy.cc b/contents/section/legacy.cc index 0b6d4eb..8e8a61c 100644 --- a/contents/section/legacy.cc +++ b/contents/section/legacy.cc @@ -34,18 +34,15 @@ Section BuildLegacySection(Context& ctx) { namespaces.emplace_back(BuildSystemDefaultNamespace(ctx)); std::set visible_apexes{ - "com.android.art", - "com.android.i18n", - "com.android.neuralnetworks", "com.android.runtime", "com.android.media", "com.android.conscrypt", "com.android.os.statsd", }; - // APEXes with JNI libs should be visible + // APEXes with JNI libs or public libs should be visible for (const auto& apex : ctx.GetApexModules()) { - if (apex.jni_libs.size() > 0) { + if (apex.jni_libs.size() > 0 || apex.public_libs.size() > 0) { visible_apexes.insert(apex.name); } } diff --git a/contents/section/product.cc b/contents/section/product.cc index ab7b25a..0b66002 100644 --- a/contents/section/product.cc +++ b/contents/section/product.cc @@ -42,14 +42,18 @@ Section BuildProductSection(Context& ctx) { namespaces.emplace_back(BuildVndkInSystemNamespace(ctx)); } - return BuildSection(ctx, - "product", - std::move(namespaces), - { - "com.android.art", - "com.android.neuralnetworks", - "com.android.runtime", - }); + std::set visible_apexes{ + "com.android.runtime", + }; + + // APEXes with public libs should be visible + for (const auto& apex : ctx.GetApexModules()) { + if (apex.public_libs.size() > 0) { + visible_apexes.insert(apex.name); + } + } + + return BuildSection(ctx, "product", std::move(namespaces), visible_apexes); } } // namespace contents } // namespace linkerconfig diff --git a/contents/section/sectionbuilder.cc b/contents/section/sectionbuilder.cc index ebe8c2d..950f8ab 100644 --- a/contents/section/sectionbuilder.cc +++ b/contents/section/sectionbuilder.cc @@ -15,6 +15,8 @@ */ #include "linkerconfig/sectionbuilder.h" +#include + #include "linkerconfig/common.h" #include "linkerconfig/log.h" #include "linkerconfig/namespace.h" @@ -35,9 +37,19 @@ Section BuildSection(const Context& ctx, const std::string& name, const LibProviders& providers) { // add additional visible APEX namespaces for (const auto& apex : ctx.GetApexModules()) { - if (visible_apexes.find(apex.name) != visible_apexes.end()) { + if (visible_apexes.find(apex.name) == visible_apexes.end()) { + continue; + } + if (auto it = std::find_if( + namespaces.begin(), + namespaces.end(), + [&apex](auto& ns) { return ns.GetName() == apex.namespace_name; }); + it == namespaces.end()) { auto ns = ctx.BuildApexNamespace(apex, true); namespaces.push_back(std::move(ns)); + } else { + // override "visible" when the apex is already created + it->SetVisible(true); } } diff --git a/contents/section/system.cc b/contents/section/system.cc index c6217bc..412f99a 100644 --- a/contents/section/system.cc +++ b/contents/section/system.cc @@ -44,18 +44,15 @@ Section BuildSystemSection(Context& ctx) { } std::set visible_apexes{ - "com.android.art", - "com.android.i18n", - "com.android.neuralnetworks", "com.android.runtime", "com.android.media", "com.android.conscrypt", "com.android.os.statsd", }; - // APEXes with JNI libs should be visible + // APEXes with JNI libs or public libs should be visible for (const auto& apex : ctx.GetApexModules()) { - if (apex.jni_libs.size() > 0) { + if (apex.jni_libs.size() > 0 || apex.public_libs.size() > 0) { visible_apexes.insert(apex.name); } } diff --git a/contents/section/unrestricted.cc b/contents/section/unrestricted.cc index f0bce5c..71f7212 100644 --- a/contents/section/unrestricted.cc +++ b/contents/section/unrestricted.cc @@ -45,18 +45,15 @@ Section BuildUnrestrictedSection(Context& ctx) { } std::set visible_apexes{ - "com.android.art", - "com.android.i18n", - "com.android.neuralnetworks", "com.android.runtime", "com.android.media", "com.android.conscrypt", "com.android.os.statsd", }; - // APEXes with JNI libs should be visible + // APEXes with JNI libs or public libs should be visible for (const auto& apex : ctx.GetApexModules()) { - if (apex.jni_libs.size() > 0) { + if (apex.jni_libs.size() > 0 || apex.public_libs.size() > 0) { visible_apexes.insert(apex.name); } } diff --git a/contents/section/vendor.cc b/contents/section/vendor.cc index 98e9e46..5bb866c 100644 --- a/contents/section/vendor.cc +++ b/contents/section/vendor.cc @@ -42,14 +42,18 @@ Section BuildVendorSection(Context& ctx) { namespaces.emplace_back(BuildVndkInSystemNamespace(ctx)); } - return BuildSection(ctx, - "vendor", - std::move(namespaces), - { - "com.android.art", - "com.android.neuralnetworks", - "com.android.runtime", - }); + std::set visible_apexes{ + "com.android.runtime", + }; + + // APEXes with public libs should be visible + for (const auto& apex : ctx.GetApexModules()) { + if (apex.public_libs.size() > 0) { + visible_apexes.insert(apex.name); + } + } + + return BuildSection(ctx, "vendor", std::move(namespaces), visible_apexes); } } // namespace contents } // namespace linkerconfig diff --git a/main.cc b/main.cc index 118130c..42d2013 100644 --- a/main.cc +++ b/main.cc @@ -270,16 +270,20 @@ void GenerateApexConfigurations(Context& ctx, const std::string& dir_path) { } } -void GenerateJniConfig(Context& ctx, const std::string& dir_path) { +void GenerateApexLibrariesConfig(Context& ctx, const std::string& dir_path) { if (dir_path == "") { return; } - std::string file_path = dir_path + "/jni.config.txt"; + const std::string file_path = dir_path + "/apex.libraries.config.txt"; std::ofstream out(file_path); for (auto const& apex_item : ctx.GetApexModules()) { if (!apex_item.jni_libs.empty()) { - out << apex_item.namespace_name << " " << Join(apex_item.jni_libs, ":") - << '\n'; + out << "jni " << apex_item.namespace_name << " " + << Join(apex_item.jni_libs, ":") << '\n'; + } + if (!apex_item.public_libs.empty()) { + out << "public " << apex_item.namespace_name << " " + << Join(apex_item.public_libs, ":") << '\n'; } } out.close(); @@ -341,7 +345,7 @@ int main(int argc, char* argv[]) { } else { ExitOnFailure(GenerateBaseLinkerConfiguration(ctx, args.target_directory)); GenerateApexConfigurations(ctx, args.target_directory); - GenerateJniConfig(ctx, args.target_directory); + GenerateApexLibrariesConfig(ctx, args.target_directory); } return EXIT_SUCCESS; diff --git a/modules/apex.cc b/modules/apex.cc index d82bab2..326bc67 100644 --- a/modules/apex.cc +++ b/modules/apex.cc @@ -15,7 +15,13 @@ */ #include "linkerconfig/apex.h" +#include +#include +#include +#include + #include +#include #include #include #include @@ -29,12 +35,47 @@ // include after log.h to avoid macro redefinition error #include "com_android_apex.h" +using android::base::ErrnoError; +using android::base::ReadFileToString; +using android::base::Result; using android::base::StartsWith; namespace { bool DirExists(const std::string& path) { return access(path.c_str(), F_OK) == 0; } + +Result> ReadPublicLibraries(const std::string& filepath) { + std::string file_content; + if (!android::base::ReadFileToString(filepath, &file_content)) { + return ErrnoError(); + } + std::vector lines = android::base::Split(file_content, "\n"); + std::set sonames; + for (auto& line : lines) { + auto trimmed_line = android::base::Trim(line); + if (trimmed_line[0] == '#' || trimmed_line.empty()) { + continue; + } + std::vector tokens = android::base::Split(trimmed_line, " "); + if (tokens.size() < 1 || tokens.size() > 3) { + return Errorf("Malformed line \"{}\"", line); + } + sonames.insert(tokens[0]); + } + return sonames; +} + +std::vector Intersect(const std::vector& as, + const std::set& bs) { + std::vector intersect; + std::copy_if(as.begin(), + as.end(), + std::back_inserter(intersect), + [&bs](const auto& a) { return bs.find(a) != bs.end(); }); + return intersect; +} + } // namespace namespace android { @@ -68,7 +109,7 @@ std::map ScanActiveApexes(const std::string& root) { } if (!apexes.empty()) { - std::string info_list_file = apex_root + "/apex-info-list.xml"; + const std::string info_list_file = apex_root + "/apex-info-list.xml"; auto info_list = com::android::apex::readApexInfoList(info_list_file.c_str()); if (info_list.has_value()) { @@ -79,6 +120,22 @@ std::map ScanActiveApexes(const std::string& root) { } else { PLOG(ERROR) << "Can't read " << info_list_file; } + + const std::string public_libraries_file = + root + "/system/etc/public.libraries.txt"; + auto public_libraries = ReadPublicLibraries(public_libraries_file); + if (public_libraries.ok()) { + for (auto& [name, apex] : apexes) { + // Only system apexes can provide public libraries. + if (!apex.InSystem()) { + continue; + } + apex.public_libs = Intersect(apex.provide_libs, *public_libraries); + } + } else { + LOG(ERROR) << "Can't read " << public_libraries_file << ": " + << public_libraries.error(); + } } return apexes; diff --git a/modules/include/linkerconfig/apex.h b/modules/include/linkerconfig/apex.h index 12c5b38..b0682bc 100644 --- a/modules/include/linkerconfig/apex.h +++ b/modules/include/linkerconfig/apex.h @@ -32,6 +32,7 @@ struct ApexInfo { std::vector require_libs; std::vector jni_libs; std::vector permitted_paths; + std::vector public_libs; bool has_bin; bool has_lib; diff --git a/testdata/golden_output/legacy/apex.libraries.config.txt b/testdata/golden_output/legacy/apex.libraries.config.txt new file mode 100644 index 0000000..950f25e --- /dev/null +++ b/testdata/golden_output/legacy/apex.libraries.config.txt @@ -0,0 +1,4 @@ +public com_android_art libnativehelper.so +jni com_android_cronet libcronet.80.0.3986.0.so +public com_android_i18n libicui18n.so:libicuuc.so +public com_android_neuralnetworks libneuralnetworks.so diff --git a/testdata/golden_output/legacy/jni.config.txt b/testdata/golden_output/legacy/jni.config.txt deleted file mode 100644 index c44e11f..0000000 --- a/testdata/golden_output/legacy/jni.config.txt +++ /dev/null @@ -1 +0,0 @@ -com_android_cronet libcronet.80.0.3986.0.so diff --git a/testdata/golden_output/product-enabled/apex.libraries.config.txt b/testdata/golden_output/product-enabled/apex.libraries.config.txt new file mode 100644 index 0000000..950f25e --- /dev/null +++ b/testdata/golden_output/product-enabled/apex.libraries.config.txt @@ -0,0 +1,4 @@ +public com_android_art libnativehelper.so +jni com_android_cronet libcronet.80.0.3986.0.so +public com_android_i18n libicui18n.so:libicuuc.so +public com_android_neuralnetworks libneuralnetworks.so diff --git a/testdata/golden_output/product-enabled/jni.config.txt b/testdata/golden_output/product-enabled/jni.config.txt deleted file mode 100644 index c44e11f..0000000 --- a/testdata/golden_output/product-enabled/jni.config.txt +++ /dev/null @@ -1 +0,0 @@ -com_android_cronet libcronet.80.0.3986.0.so diff --git a/testdata/golden_output/product-enabled/ld.config.txt b/testdata/golden_output/product-enabled/ld.config.txt index b93d2f0..2d1567f 100644 --- a/testdata/golden_output/product-enabled/ld.config.txt +++ b/testdata/golden_output/product-enabled/ld.config.txt @@ -536,6 +536,7 @@ namespace.com_android_art.link.com_android_i18n.shared_libs += libicui18n.so namespace.com_android_art.link.com_android_i18n.shared_libs += libicuuc.so namespace.com_android_art.link.com_android_neuralnetworks.shared_libs = libneuralnetworks.so namespace.com_android_i18n.isolated = true +namespace.com_android_i18n.visible = true namespace.com_android_i18n.search.paths = /apex/com.android.i18n/${LIB} namespace.com_android_i18n.permitted.paths = /apex/com.android.i18n/${LIB} namespace.com_android_i18n.permitted.paths += /system/${LIB} @@ -702,6 +703,7 @@ namespace.com_android_art.link.com_android_i18n.shared_libs += libicui18n.so namespace.com_android_art.link.com_android_i18n.shared_libs += libicuuc.so namespace.com_android_art.link.com_android_neuralnetworks.shared_libs = libneuralnetworks.so namespace.com_android_i18n.isolated = true +namespace.com_android_i18n.visible = true namespace.com_android_i18n.search.paths = /apex/com.android.i18n/${LIB} namespace.com_android_i18n.permitted.paths = /apex/com.android.i18n/${LIB} namespace.com_android_i18n.permitted.paths += /system/${LIB} diff --git a/testdata/golden_output/stage0/jni.config.txt b/testdata/golden_output/stage0/apex.libraries.config.txt similarity index 100% rename from testdata/golden_output/stage0/jni.config.txt rename to testdata/golden_output/stage0/apex.libraries.config.txt diff --git a/testdata/golden_output/stage1/apex.libraries.config.txt b/testdata/golden_output/stage1/apex.libraries.config.txt new file mode 100644 index 0000000..29a73f5 --- /dev/null +++ b/testdata/golden_output/stage1/apex.libraries.config.txt @@ -0,0 +1,2 @@ +public com_android_art libnativehelper.so +public com_android_i18n libicui18n.so:libicuuc.so diff --git a/testdata/golden_output/stage1/jni.config.txt b/testdata/golden_output/stage1/jni.config.txt deleted file mode 100644 index e69de29..0000000 diff --git a/testdata/golden_output/stage1/ld.config.txt b/testdata/golden_output/stage1/ld.config.txt index 2cd3ffb..ebc4178 100644 --- a/testdata/golden_output/stage1/ld.config.txt +++ b/testdata/golden_output/stage1/ld.config.txt @@ -348,6 +348,7 @@ namespace.com_android_art.link.com_android_i18n.shared_libs += libicu_jni.so namespace.com_android_art.link.com_android_i18n.shared_libs += libicui18n.so namespace.com_android_art.link.com_android_i18n.shared_libs += libicuuc.so namespace.com_android_i18n.isolated = true +namespace.com_android_i18n.visible = true namespace.com_android_i18n.search.paths = /apex/com.android.i18n/${LIB} namespace.com_android_i18n.permitted.paths = /apex/com.android.i18n/${LIB} namespace.com_android_i18n.permitted.paths += /system/${LIB} diff --git a/testdata/golden_output/stage2/apex.libraries.config.txt b/testdata/golden_output/stage2/apex.libraries.config.txt new file mode 100644 index 0000000..950f25e --- /dev/null +++ b/testdata/golden_output/stage2/apex.libraries.config.txt @@ -0,0 +1,4 @@ +public com_android_art libnativehelper.so +jni com_android_cronet libcronet.80.0.3986.0.so +public com_android_i18n libicui18n.so:libicuuc.so +public com_android_neuralnetworks libneuralnetworks.so diff --git a/testdata/golden_output/stage2/jni.config.txt b/testdata/golden_output/stage2/jni.config.txt deleted file mode 100644 index c44e11f..0000000 --- a/testdata/golden_output/stage2/jni.config.txt +++ /dev/null @@ -1 +0,0 @@ -com_android_cronet libcronet.80.0.3986.0.so diff --git a/testdata/golden_output/stage2/ld.config.txt b/testdata/golden_output/stage2/ld.config.txt index 155ab83..a755ded 100644 --- a/testdata/golden_output/stage2/ld.config.txt +++ b/testdata/golden_output/stage2/ld.config.txt @@ -524,6 +524,7 @@ namespace.com_android_art.link.com_android_i18n.shared_libs += libicui18n.so namespace.com_android_art.link.com_android_i18n.shared_libs += libicuuc.so namespace.com_android_art.link.com_android_neuralnetworks.shared_libs = libneuralnetworks.so namespace.com_android_i18n.isolated = true +namespace.com_android_i18n.visible = true namespace.com_android_i18n.search.paths = /apex/com.android.i18n/${LIB} namespace.com_android_i18n.permitted.paths = /apex/com.android.i18n/${LIB} namespace.com_android_i18n.permitted.paths += /system/${LIB} diff --git a/testdata/root/system/etc/public.libraries.txt b/testdata/root/system/etc/public.libraries.txt new file mode 100644 index 0000000..5de422f --- /dev/null +++ b/testdata/root/system/etc/public.libraries.txt @@ -0,0 +1,29 @@ +# See https://android.googlesource.com/platform/ndk/+/master/docs/PlatformApis.md +libandroid.so +libaaudio.so +libamidi.so +libbinder_ndk.so +libc.so +libcamera2ndk.so +libdl.so +libEGL.so +libGLESv1_CM.so +libGLESv2.so +libGLESv3.so +libicui18n.so +libicuuc.so +libjnigraphics.so +liblog.so +libmediandk.so +libm.so +libnativehelper.so +libnativewindow.so +libneuralnetworks.so nopreload +libOpenMAXAL.so +libOpenSLES.so +libRS.so +libstdc++.so +libsync.so +libvulkan.so +libwebviewchromium_plat_support.so +libz.so -- 2.11.0