Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6b20b7cf authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "add nopreload option in public.libraries.txt"

parents b21f3dd7 5db5d198
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -124,7 +124,7 @@ void LibraryNamespaces::Initialize() {
  // we might as well end up loading them from /system/lib or /product/lib
  // we might as well end up loading them from /system/lib or /product/lib
  // For now we rely on CTS test to catch things like this but
  // For now we rely on CTS test to catch things like this but
  // it should probably be addressed in the future.
  // it should probably be addressed in the future.
  for (const auto& soname : android::base::Split(default_public_libraries(), ":")) {
  for (const auto& soname : android::base::Split(preloadable_public_libraries(), ":")) {
    LOG_ALWAYS_FATAL_IF(dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE) == nullptr,
    LOG_ALWAYS_FATAL_IF(dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE) == nullptr,
                        "Error preloading public library %s: %s", soname.c_str(), dlerror());
                        "Error preloading public library %s: %s", soname.c_str(), dlerror());
  }
  }
+84 −1
Original line number Original line Diff line number Diff line
@@ -29,6 +29,7 @@
#include "public_libraries.h"
#include "public_libraries.h"


using namespace ::testing;
using namespace ::testing;
using namespace ::android::nativeloader::internal;


namespace android {
namespace android {
namespace nativeloader {
namespace nativeloader {
@@ -289,7 +290,7 @@ class NativeLoaderTest : public ::testing::TestWithParam<bool> {


  void SetExpectations() {
  void SetExpectations() {
    std::vector<std::string> default_public_libs =
    std::vector<std::string> default_public_libs =
        android::base::Split(default_public_libraries(), ":");
        android::base::Split(preloadable_public_libraries(), ":");
    for (auto l : default_public_libs) {
    for (auto l : default_public_libs) {
      EXPECT_CALL(*mock, dlopen(StrEq(l.c_str()), RTLD_NOW | RTLD_NODELETE))
      EXPECT_CALL(*mock, dlopen(StrEq(l.c_str()), RTLD_NOW | RTLD_NODELETE))
          .WillOnce(Return(any_nonnull));
          .WillOnce(Return(any_nonnull));
@@ -576,5 +577,87 @@ TEST_P(NativeLoaderTest_Create, TwoApks) {


INSTANTIATE_TEST_SUITE_P(NativeLoaderTests_Create, NativeLoaderTest_Create, testing::Bool());
INSTANTIATE_TEST_SUITE_P(NativeLoaderTests_Create, NativeLoaderTest_Create, testing::Bool());


const std::function<Result<bool>(const struct ConfigEntry&)> always_true =
    [](const struct ConfigEntry&) -> Result<bool> { return true; };

TEST(NativeLoaderConfigParser, NamesAndComments) {
  const char file_content[] = R"(
######

libA.so
#libB.so


      libC.so
libD.so
    #### libE.so
)";
  const std::vector<std::string> expected_result = {"libA.so", "libC.so", "libD.so"};
  Result<std::vector<std::string>> result = ParseConfig(file_content, always_true);
  ASSERT_TRUE(result) << result.error().message();
  ASSERT_EQ(expected_result, *result);
}

TEST(NativeLoaderConfigParser, WithBitness) {
  const char file_content[] = R"(
libA.so 32
libB.so 64
libC.so
)";
#if defined(__LP64__)
  const std::vector<std::string> expected_result = {"libB.so", "libC.so"};
#else
  const std::vector<std::string> expected_result = {"libA.so", "libC.so"};
#endif
  Result<std::vector<std::string>> result = ParseConfig(file_content, always_true);
  ASSERT_TRUE(result) << result.error().message();
  ASSERT_EQ(expected_result, *result);
}

TEST(NativeLoaderConfigParser, WithNoPreload) {
  const char file_content[] = R"(
libA.so nopreload
libB.so nopreload
libC.so
)";

  const std::vector<std::string> expected_result = {"libC.so"};
  Result<std::vector<std::string>> result =
      ParseConfig(file_content,
                  [](const struct ConfigEntry& entry) -> Result<bool> { return !entry.nopreload; });
  ASSERT_TRUE(result) << result.error().message();
  ASSERT_EQ(expected_result, *result);
}

TEST(NativeLoaderConfigParser, WithNoPreloadAndBitness) {
  const char file_content[] = R"(
libA.so nopreload 32
libB.so 64 nopreload
libC.so 32
libD.so 64
libE.so nopreload
)";

#if defined(__LP64__)
  const std::vector<std::string> expected_result = {"libD.so"};
#else
  const std::vector<std::string> expected_result = {"libC.so"};
#endif
  Result<std::vector<std::string>> result =
      ParseConfig(file_content,
                  [](const struct ConfigEntry& entry) -> Result<bool> { return !entry.nopreload; });
  ASSERT_TRUE(result) << result.error().message();
  ASSERT_EQ(expected_result, *result);
}

TEST(NativeLoaderConfigParser, RejectMalformed) {
  ASSERT_FALSE(ParseConfig("libA.so 32 64", always_true));
  ASSERT_FALSE(ParseConfig("libA.so 32 32", always_true));
  ASSERT_FALSE(ParseConfig("libA.so 32 nopreload 64", always_true));
  ASSERT_FALSE(ParseConfig("32 libA.so nopreload", always_true));
  ASSERT_FALSE(ParseConfig("nopreload libA.so 32", always_true));
  ASSERT_FALSE(ParseConfig("libA.so nopreload # comment", always_true));
}

}  // namespace nativeloader
}  // namespace nativeloader
}  // namespace android
}  // namespace android
+87 −49
Original line number Original line Diff line number Diff line
@@ -34,7 +34,8 @@


namespace android::nativeloader {
namespace android::nativeloader {


using namespace std::string_literals;
using namespace internal;
using namespace ::std::string_literals;
using android::base::ErrnoError;
using android::base::ErrnoError;
using android::base::Errorf;
using android::base::Errorf;
using android::base::Result;
using android::base::Result;
@@ -95,53 +96,21 @@ void InsertVndkVersionStr(std::string* file_name) {
  file_name->insert(insert_pos, vndk_version_str());
  file_name->insert(insert_pos, vndk_version_str());
}
}


const std::function<Result<void>(const std::string&)> always_true =
const std::function<Result<bool>(const struct ConfigEntry&)> always_true =
    [](const std::string&) -> Result<void> { return {}; };
    [](const struct ConfigEntry&) -> Result<bool> { return true; };


Result<std::vector<std::string>> ReadConfig(
Result<std::vector<std::string>> ReadConfig(
    const std::string& configFile,
    const std::string& configFile,
    const std::function<Result<void>(const std::string& /* soname */)>& check_soname) {
    const std::function<Result<bool>(const ConfigEntry& /* entry */)>& filter_fn) {
  // Read list of public native libraries from the config file.
  std::string file_content;
  std::string file_content;
  if (!base::ReadFileToString(configFile, &file_content)) {
  if (!base::ReadFileToString(configFile, &file_content)) {
    return ErrnoError();
    return ErrnoError();
  }
  }

  Result<std::vector<std::string>> result = ParseConfig(file_content, filter_fn);
  std::vector<std::string> lines = base::Split(file_content, "\n");
  if (!result) {

    return Errorf("Cannot parse {}: {}", configFile, result.error().message());
  std::vector<std::string> sonames;
  for (auto& line : lines) {
    auto trimmed_line = base::Trim(line);
    if (trimmed_line[0] == '#' || trimmed_line.empty()) {
      continue;
    }
    size_t space_pos = trimmed_line.rfind(' ');
    if (space_pos != std::string::npos) {
      std::string type = trimmed_line.substr(space_pos + 1);
      if (type != "32" && type != "64") {
        return Errorf("Malformed line: {}", line);
      }
#if defined(__LP64__)
      // Skip 32 bit public library.
      if (type == "32") {
        continue;
      }
#else
      // Skip 64 bit public library.
      if (type == "64") {
        continue;
  }
  }
#endif
  return result;
      trimmed_line.resize(space_pos);
    }

    auto ret = check_soname(trimmed_line);
    if (!ret) {
      return ret.error();
    }
    sonames.push_back(trimmed_line);
  }
  return sonames;
}
}


void ReadExtensionLibraries(const char* dirname, std::vector<std::string>* sonames) {
void ReadExtensionLibraries(const char* dirname, std::vector<std::string>* sonames) {
@@ -165,13 +134,13 @@ void ReadExtensionLibraries(const char* dirname, std::vector<std::string>* sonam
            config_file_path.c_str());
            config_file_path.c_str());


        auto ret = ReadConfig(
        auto ret = ReadConfig(
            config_file_path, [&company_name](const std::string& soname) -> Result<void> {
            config_file_path, [&company_name](const struct ConfigEntry& entry) -> Result<bool> {
              if (android::base::StartsWith(soname, "lib") &&
              if (android::base::StartsWith(entry.soname, "lib") &&
                  android::base::EndsWith(soname, "." + company_name + ".so")) {
                  android::base::EndsWith(entry.soname, "." + company_name + ".so")) {
                return {};
                return true;
              } else {
              } else {
                return Errorf("Library name \"{}\" does not end with the company name {}.", soname,
                return Errorf("Library name \"{}\" does not end with the company name {}.",
                              company_name);
                              entry.soname, company_name);
              }
              }
            });
            });
        if (ret) {
        if (ret) {
@@ -185,9 +154,16 @@ void ReadExtensionLibraries(const char* dirname, std::vector<std::string>* sonam
  }
  }
}
}


static std::string InitDefaultPublicLibraries() {
static std::string InitDefaultPublicLibraries(bool for_preload) {
  std::string config_file = root_dir() + kDefaultPublicLibrariesFile;
  std::string config_file = root_dir() + kDefaultPublicLibrariesFile;
  auto sonames = ReadConfig(config_file, always_true);
  auto sonames =
      ReadConfig(config_file, [&for_preload](const struct ConfigEntry& entry) -> Result<bool> {
        if (for_preload) {
          return !entry.nopreload;
        } else {
          return true;
        }
      });
  if (!sonames) {
  if (!sonames) {
    LOG_ALWAYS_FATAL("Error reading public native library list from \"%s\": %s",
    LOG_ALWAYS_FATAL("Error reading public native library list from \"%s\": %s",
                     config_file.c_str(), sonames.error().message().c_str());
                     config_file.c_str(), sonames.error().message().c_str());
@@ -290,8 +266,13 @@ static std::string InitNeuralNetworksPublicLibraries() {


}  // namespace
}  // namespace


const std::string& preloadable_public_libraries() {
  static std::string list = InitDefaultPublicLibraries(/*for_preload*/ true);
  return list;
}

const std::string& default_public_libraries() {
const std::string& default_public_libraries() {
  static std::string list = InitDefaultPublicLibraries();
  static std::string list = InitDefaultPublicLibraries(/*for_preload*/ false);
  return list;
  return list;
}
}


@@ -325,4 +306,61 @@ const std::string& vndksp_libraries() {
  return list;
  return list;
}
}


namespace internal {
// Exported for testing
Result<std::vector<std::string>> ParseConfig(
    const std::string& file_content,
    const std::function<Result<bool>(const ConfigEntry& /* entry */)>& filter_fn) {
  std::vector<std::string> lines = base::Split(file_content, "\n");

  std::vector<std::string> sonames;
  for (auto& line : lines) {
    auto trimmed_line = base::Trim(line);
    if (trimmed_line[0] == '#' || trimmed_line.empty()) {
      continue;
    }

    std::vector<std::string> tokens = android::base::Split(trimmed_line, " ");
    if (tokens.size() < 1 || tokens.size() > 3) {
      return Errorf("Malformed line \"{}\"", line);
    }
    struct ConfigEntry entry = {.soname = "", .nopreload = false, .bitness = ALL};
    size_t i = tokens.size();
    while (i-- > 0) {
      if (tokens[i] == "nopreload") {
        entry.nopreload = true;
      } else if (tokens[i] == "32" || tokens[i] == "64") {
        if (entry.bitness != ALL) {
          return Errorf("Malformed line \"{}\": bitness can be specified only once", line);
        }
        entry.bitness = tokens[i] == "32" ? ONLY_32 : ONLY_64;
      } else {
        if (i != 0) {
          return Errorf("Malformed line \"{}\"", line);
        }
        entry.soname = tokens[i];
      }
    }

    // skip 32-bit lib on 64-bit process and vice versa
#if defined(__LP64__)
    if (entry.bitness == ONLY_32) continue;
#else
    if (entry.bitness == ONLY_64) continue;
#endif

    Result<bool> ret = filter_fn(entry);
    if (!ret) {
      return ret.error();
    }
    if (*ret) {
      // filter_fn has returned true.
      sonames.push_back(entry.soname);
    }
  }
  return sonames;
}

}  // namespace internal

}  // namespace android::nativeloader
}  // namespace android::nativeloader
+24 −1
Original line number Original line Diff line number Diff line
@@ -15,13 +15,19 @@
 */
 */
#pragma once
#pragma once


#include <algorithm>
#include <string>
#include <string>


#include <android-base/result.h>

namespace android::nativeloader {
namespace android::nativeloader {


using android::base::Result;

// These provide the list of libraries that are available to the namespace for apps.
// These provide the list of libraries that are available to the namespace for apps.
// Not all of the libraries are available to apps. Depending on the context,
// Not all of the libraries are available to apps. Depending on the context,
// e.g., if it is a vendor app or not, different set of libraries are made available.
// e.g., if it is a vendor app or not, different set of libraries are made available.
const std::string& preloadable_public_libraries();
const std::string& default_public_libraries();
const std::string& default_public_libraries();
const std::string& runtime_public_libraries();
const std::string& runtime_public_libraries();
const std::string& vendor_public_libraries();
const std::string& vendor_public_libraries();
@@ -30,4 +36,21 @@ const std::string& neuralnetworks_public_libraries();
const std::string& llndk_libraries();
const std::string& llndk_libraries();
const std::string& vndksp_libraries();
const std::string& vndksp_libraries();


};  // namespace android::nativeloader
// These are exported for testing
namespace internal {

enum Bitness { ALL = 0, ONLY_32, ONLY_64 };

struct ConfigEntry {
  std::string soname;
  bool nopreload;
  Bitness bitness;
};

Result<std::vector<std::string>> ParseConfig(
    const std::string& file_content,
    const std::function<Result<bool>(const ConfigEntry& /* entry */)>& filter_fn);

}  // namespace internal

}  // namespace android::nativeloader