std::vector<DirToSection> dirToSection = {
{"/system/bin/", "system"},
{"/system/xbin/", "system"},
- {"/" + Var("SYSTEM_EXT", "system_ext") + "/bin/", "system"},
+ {Var("SYSTEM_EXT") + "/bin/", "system"},
// Processes from the product partition will have a separate section if
// PRODUCT_PRODUCT_VNDK_VERSION is defined. Otherwise, they are run from
// the "system" section.
- {"/" + Var("PRODUCT", "product") + "/bin/", "product"},
+ {Var("PRODUCT") + "/bin/", "product"},
{"/odm/bin/", "vendor"},
{"/vendor/bin/", "vendor"},
const std::vector<DirToSection> kDirToSection = {
// All binaries gets the same configuration 'legacy'
{"/system", "legacy"},
- {"/" + Var("SYSTEM_EXT", "system_ext"), "legacy"},
- {"/" + Var("PRODUCT", "product"), "legacy"},
+ {Var("SYSTEM_EXT"), "legacy"},
+ {Var("PRODUCT"), "legacy"},
{"/vendor", "legacy"},
{"/odm", "legacy"},
{"/sbin", "legacy"},
Namespace ns("default", /*is_isolated=*/false,
/*is_visible=*/false);
ns.AddSearchPath("/system/${LIB}", AsanPath::NONE);
- ns.AddSearchPath("/" + Var("SYSTEM_EXT", "system_ext") + "/${LIB}",
- AsanPath::NONE);
- ns.AddSearchPath("/" + Var("PRODUCT", "product") + "/${LIB}", AsanPath::NONE);
+ ns.AddSearchPath(Var("SYSTEM_EXT") + "/${LIB}", AsanPath::NONE);
+ ns.AddSearchPath(Var("PRODUCT") + "/${LIB}", AsanPath::NONE);
return ns;
}
Namespace BuildProductDefaultNamespace([[maybe_unused]] const Context& ctx) {
Namespace ns("default", /*is_isolated=*/true, /*is_visible=*/true);
- ns.AddSearchPath("/" + Var("PRODUCT", "product") + "/${LIB}",
+ ns.AddSearchPath(Var("PRODUCT", "product") + "/${LIB}",
AsanPath::WITH_DATA_ASAN);
- ns.AddPermittedPath("/" + Var("PRODUCT", "product"), AsanPath::WITH_DATA_ASAN);
+ ns.AddPermittedPath(Var("PRODUCT", "product"), AsanPath::WITH_DATA_ASAN);
ns.GetLink(ctx.GetSystemNamespaceName())
.AddSharedLib(Var("LLNDK_LIBRARIES_PRODUCT"));
Namespace BuildSystemNamespace([[maybe_unused]] const Context& ctx) {
Namespace ns("system", /*is_isolated=*/false, /*is_visible=*/false);
ns.AddSearchPath("/system/${LIB}", AsanPath::WITH_DATA_ASAN);
- ns.AddSearchPath("/" + Var("SYSTEM_EXT", "system_ext") + "/${LIB}",
- AsanPath::WITH_DATA_ASAN);
+ ns.AddSearchPath(Var("SYSTEM_EXT") + "/${LIB}", AsanPath::WITH_DATA_ASAN);
if (!IsProductVndkVersionDefined()) {
- ns.AddSearchPath("/" + Var("PRODUCT", "product") + "/${LIB}",
- AsanPath::WITH_DATA_ASAN);
+ ns.AddSearchPath(Var("PRODUCT") + "/${LIB}", AsanPath::WITH_DATA_ASAN);
}
ns.AddRequires(std::vector{"libdexfile_external.so",
namespace contents {
Namespace BuildSystemDefaultNamespace([[maybe_unused]] const Context& ctx) {
bool is_fully_treblelized = ctx.IsDefaultConfig();
- std::string product = Var("PRODUCT", "product");
- std::string system_ext = Var("SYSTEM_EXT", "system_ext");
+ std::string product = Var("PRODUCT");
+ std::string system_ext = Var("SYSTEM_EXT");
// Visible to allow links to be created at runtime, e.g. through
// android_link_namespaces in libnativeloader.
/*is_visible=*/true);
ns.AddSearchPath("/system/${LIB}", AsanPath::WITH_DATA_ASAN);
- ns.AddSearchPath("/" + system_ext + "/${LIB}", AsanPath::WITH_DATA_ASAN);
+ ns.AddSearchPath(system_ext + "/${LIB}", AsanPath::WITH_DATA_ASAN);
if (!IsProductVndkVersionDefined() || !is_fully_treblelized) {
// System processes can search product libs only if product VNDK is not
// enforced.
- ns.AddSearchPath("/" + product + "/${LIB}", AsanPath::WITH_DATA_ASAN);
+ ns.AddSearchPath(product + "/${LIB}", AsanPath::WITH_DATA_ASAN);
}
if (!is_fully_treblelized) {
ns.AddSearchPath("/vendor/${LIB}", AsanPath::WITH_DATA_ASAN);
"/system/${LIB}/drm",
"/system/${LIB}/extractors",
"/system/${LIB}/hw",
- "/" + system_ext + "/${LIB}",
+ system_ext + "/${LIB}",
// These are where odex files are located. libart has to be able to
// dlopen the files
"/system/app",
"/system/priv-app",
- "/" + system_ext + "/framework",
- "/" + system_ext + "/app",
- "/" + system_ext + "/priv-app",
+ system_ext + "/framework",
+ system_ext + "/app",
+ system_ext + "/priv-app",
"/vendor/framework",
"/vendor/app",
"/vendor/priv-app",
"/odm/app",
"/odm/priv-app",
"/oem/app",
- "/" + product + "/framework",
- "/" + product + "/app",
- "/" + product + "/priv-app",
+ product + "/framework",
+ product + "/app",
+ product + "/priv-app",
"/data",
"/mnt/expand",
"/apex/com.android.runtime/${LIB}/bionic",
}
if (!IsProductVndkVersionDefined()) {
// System processes can use product libs only if product VNDK is not enforced.
- ns.AddPermittedPath("/" + product + "/${LIB}", AsanPath::SAME_PATH);
+ ns.AddPermittedPath(product + "/${LIB}", AsanPath::SAME_PATH);
}
}
// VNDK-Lite devices require broader access from vendor to system/product partition
if (is_vndklite) {
ns.AddSearchPath("/system/${LIB}", AsanPath::WITH_DATA_ASAN);
- ns.AddSearchPath("/" + Var("SYSTEM_EXT", "system_ext") + "/${LIB}",
- AsanPath::WITH_DATA_ASAN);
- ns.AddSearchPath("/" + Var("PRODUCT", "product") + "/${LIB}",
- AsanPath::WITH_DATA_ASAN);
+ ns.AddSearchPath(Var("SYSTEM_EXT") + "/${LIB}", AsanPath::WITH_DATA_ASAN);
+ ns.AddSearchPath(Var("PRODUCT") + "/${LIB}", AsanPath::WITH_DATA_ASAN);
// Put system vndk at the last search order in vndk_lite for GSI
ns.AddSearchPath(
"/apex/com.android.vndk.v" + Var("VENDOR_VNDK_VERSION") + "/${LIB}",
// The search paths here should be kept the same as that of the 'system' namespace.
ns.AddSearchPath("/system/${LIB}", AsanPath::WITH_DATA_ASAN);
- ns.AddSearchPath("/" + Var("SYSTEM_EXT", "system_ext") + "/${LIB}",
- AsanPath::WITH_DATA_ASAN);
+ ns.AddSearchPath(Var("SYSTEM_EXT") + "/${LIB}", AsanPath::WITH_DATA_ASAN);
if (!IsProductVndkVersionDefined()) {
- ns.AddSearchPath("/" + Var("PRODUCT", "product") + "/${LIB}",
- AsanPath::WITH_DATA_ASAN);
+ ns.AddSearchPath(Var("PRODUCT") + "/${LIB}", AsanPath::WITH_DATA_ASAN);
}
if (android::linkerconfig::modules::IsVndkInSystemNamespace()) {
MockVndkVariables("PRODUCT", vndk_ver);
Variables::AddValue("ro.product.vndk.version", vndk_ver);
+ Variables::AddValue("SYSTEM_EXT", "/system_ext");
+ Variables::AddValue("PRODUCT", "/procut");
+
Variables::AddValue("VNDK_USING_CORE_VARIANT_LIBRARIES",
"vndk_using_core_variant_libraries");
Variables::AddValue("STUB_LIBRARIES", "stub_libraries");
#include "linkerconfig/environment.h"
#include "linkerconfig/librarylistloader.h"
#include "linkerconfig/log.h"
+#include "linkerconfig/stringutil.h"
#include "linkerconfig/variables.h"
using android::base::Result;
using android::linkerconfig::modules::GetProductVndkVersion;
using android::linkerconfig::modules::GetVendorVndkVersion;
+using android::linkerconfig::modules::TrimPrefix;
using android::linkerconfig::modules::Variables;
namespace {
Result<std::string> GetRealPath(std::string target_path) {
char resolved_path[PATH_MAX];
if (realpath(target_path.c_str(), resolved_path) != nullptr) {
- int start_index = 0;
- if (resolved_path[0] == '/') {
- start_index = 1;
- }
- return &resolved_path[start_index];
+ return resolved_path;
}
return ErrnoErrorf("Failed to get realpath from {}", target_path);
}
-void LoadVariableFromPartitionPath(std::string variable_name, std::string path) {
- auto real_path = GetRealPath(path);
+void LoadVariableFromPartitionPath(const std::string& root,
+ std::string variable_name,
+ std::string partition) {
+ auto real_path = GetRealPath(root + partition);
if (real_path.ok()) {
- Variables::AddValue(variable_name, *real_path);
+ Variables::AddValue(variable_name, TrimPrefix(*real_path, root));
} else {
LOG(WARNING) << real_path.error();
+ Variables::AddValue(variable_name, partition);
}
}
void LoadPartitionPathVariables(const std::string& root) {
// TODO(b/141714913): generalize path handling
- LoadVariableFromPartitionPath("PRODUCT", root + "/product");
- LoadVariableFromPartitionPath("SYSTEM_EXT", root + "/system_ext");
+ LoadVariableFromPartitionPath(root, "PRODUCT", "/product");
+ LoadVariableFromPartitionPath(root, "SYSTEM_EXT", "/system_ext");
}
void LoadVndkLibraryListVariables(const std::string& root,
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include <android-base/result.h>
-#include <getopt.h>
+#include <climits>
+#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include <errno.h>
#include <fcntl.h>
+#include <getopt.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <android-base/result.h>
+
#include "linkerconfig/apex.h"
#include "linkerconfig/apexconfig.h"
#include "linkerconfig/baseconfig.h"
exit(status);
}
+std::string RealPath(std::string_view path) {
+ char resolved_path[PATH_MAX];
+ if (realpath(path.data(), resolved_path) != nullptr) {
+ return resolved_path;
+ }
+ PrintUsage(-1);
+}
+
bool ParseArgs(int argc, char* argv[], ProgramArgs* args) {
int parse_result;
while ((parse_result = getopt_long(
args->strict = true;
break;
case 'r':
- args->root = optarg;
+ args->root = RealPath(optarg);
break;
case 'v':
args->vndk_version = optarg;
}
Context GetContext(ProgramArgs args) {
- const std::string apex_root = args.root + "/apex";
- auto apex_list = android::linkerconfig::modules::ScanActiveApexes(apex_root);
+ auto apex_list = android::linkerconfig::modules::ScanActiveApexes(args.root);
Context ctx;
for (auto const& apex_item : apex_list) {
auto apex_info = apex_item.second;
#include <apexutil.h>
+#include "linkerconfig/stringutil.h"
+
namespace {
+
bool DirExists(const std::string& path) {
return access(path.c_str(), F_OK) == 0;
}
+
} // namespace
namespace android {
namespace linkerconfig {
namespace modules {
-std::map<std::string, ApexInfo> ScanActiveApexes(const std::string& apex_root) {
+
+std::map<std::string, ApexInfo> ScanActiveApexes(const std::string& root) {
std::map<std::string, ApexInfo> apexes;
+ const auto apex_root = root + apex::kApexRoot;
for (const auto& [path, manifest] : apex::GetActivePackages(apex_root)) {
bool has_bin = DirExists(path + "/bin");
bool has_lib = DirExists(path + "/lib") || DirExists(path + "/lib64");
ApexInfo info(manifest.name(),
- path,
+ TrimPrefix(path, root),
{manifest.providenativelibs().begin(),
manifest.providenativelibs().end()},
{manifest.requirenativelibs().begin(),
}
return apexes;
}
+
} // namespace modules
} // namespace linkerconfig
} // namespace android
\ No newline at end of file
}
};
-std::map<std::string, ApexInfo> ScanActiveApexes(const std::string& apex_root);
+std::map<std::string, ApexInfo> ScanActiveApexes(const std::string& root);
} // namespace modules
} // namespace linkerconfig
} // namespace android
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <string>
+
+namespace android {
+namespace linkerconfig {
+namespace modules {
+std::string TrimPrefix(const std::string& s, const std::string& prefix);
+}
+} // namespace linkerconfig
+} // namespace android
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "linkerconfig/stringutil.h"
+
+#include <android-base/strings.h>
+
+namespace android {
+namespace linkerconfig {
+namespace modules {
+std::string TrimPrefix(const std::string& s, const std::string& prefix) {
+ if (android::base::StartsWith(s, prefix)) {
+ return s.substr(prefix.size());
+ }
+ return s;
+}
+} // namespace modules
+} // namespace linkerconfig
+} // namespace android
\ No newline at end of file
TEST_F(ApexTest, scan_apex_dir) {
PrepareApex("foo", {}, {"bar.so"});
- WriteFile("foo/bin/foo", "");
+ WriteFile("/apex/foo/bin/foo", "");
PrepareApex("bar", {"bar.so"}, {});
- WriteFile("bar/lib64/bar.so", "");
+ WriteFile("/apex/bar/lib64/bar.so", "");
- auto apexes = ScanActiveApexes(apex_root);
+ auto apexes = ScanActiveApexes(root);
ASSERT_EQ(2U, apexes.size());
ASSERT_THAT(apexes["foo"].require_libs, Contains("bar.so"));
#include "linkerconfig/apex.h"
+#include <iostream>
+
struct ApexTest : ::testing::Test {
TemporaryDir tmp_dir;
- std::string apex_root;
+ std::string root;
void SetUp() override {
- apex_root = tmp_dir.path + std::string("/");
+ root = tmp_dir.path;
}
android::linkerconfig::modules::ApexInfo PrepareApex(
for (auto lib : required_libs) {
manifest.add_requirenativelibs(lib);
}
- WriteFile(apex_name + "/apex_manifest.pb", manifest.SerializeAsString());
+ const auto apex_path = "/apex/" + apex_name;
+ WriteFile(apex_path + "/apex_manifest.pb", manifest.SerializeAsString());
return android::linkerconfig::modules::ApexInfo(
manifest.name(),
- tmp_dir.path,
+ apex_path,
{manifest.providenativelibs().begin(),
manifest.providenativelibs().end()},
{manifest.requirenativelibs().begin(),
void Mkdir(std::string dir_path) {
if (access(dir_path.c_str(), F_OK) == 0) return;
Mkdir(android::base::Dirname(dir_path));
+ std::cout << "mkdir(" + dir_path + ")\n";
ASSERT_NE(-1, mkdir(dir_path.c_str(), 0755) == -1)
<< "Failed to create a directory: " << dir_path;
}
void WriteFile(std::string file, std::string content) {
- std::string file_path = apex_root + file;
+ std::string file_path = root + file;
Mkdir(::android::base::Dirname(file_path));
+ std::cout << "writeFile(" + file_path + ")\n";
ASSERT_TRUE(::android::base::WriteStringToFile(content, file_path))
<< "Failed to write a file: " << file_path;
}