Define product public libraries

When /product is unbundled from the /system, /product/etc/ may not
have 'public.libraries-<companyname>.txt' to extend public libraries.
Instead, /product/etc/public.library.txt can provide public libraries
from /product.

Bug: 186055799
Test: atest libnativeloader_test
Change-Id: I8994649826657f59ac1dac655205b9704a2c67c9
diff --git a/libnativeloader/library_namespaces.cpp b/libnativeloader/library_namespaces.cpp
index 8b87338..585e98a 100644
--- a/libnativeloader/library_namespaces.cpp
+++ b/libnativeloader/library_namespaces.cpp
@@ -47,7 +47,12 @@
 // to use to load vendor libraries to separate namespace with controlled interface between
 // vendor and system namespaces.
 constexpr const char* kVendorNamespaceName = "sphal";
+// Similar to sphal namespace, product namespace provides some product libraries.
+constexpr const char* kProductNamespaceName = "product";
+
+// vndk namespace for unbundled vendor apps
 constexpr const char* kVndkNamespaceName = "vndk";
+// vndk_product namespace for unbundled product apps
 constexpr const char* kVndkProductNamespaceName = "vndk_product";
 
 // classloader-namespace is a linker namespace that is created for the loaded
@@ -374,6 +379,27 @@
     }
   }
 
+  auto product_libs = filter_public_libraries(target_sdk_version, uses_libraries,
+                                              product_public_libraries());
+  if (!product_libs.empty()) {
+    auto target_ns = system_ns;
+    if (is_product_vndk_version_defined()) {
+      // If ro.product.vndk.version is defined, product namespace provides the product libraries.
+      target_ns = NativeLoaderNamespace::GetExportedNamespace(kProductNamespaceName, is_bridged);
+    }
+    if (target_ns.ok()) {
+      linked = app_ns->Link(&target_ns.value(), product_libs);
+      if (!linked.ok()) {
+        return linked.error();
+      }
+    } else {
+      // The linkerconfig must have a problem on defining the product namespace in the system
+      // section. Skip linking product namespace. This will not affect most of the apps. Only the
+      // apps that requires the product public libraries will fail.
+      ALOGW("Namespace for product libs not found: %s", target_ns.error().message().c_str());
+    }
+  }
+
   auto& emplaced = namespaces_.emplace_back(
       std::make_pair(env->NewWeakGlobalRef(class_loader), *app_ns));
   if (is_main_classloader) {
diff --git a/libnativeloader/native_loader_test.cpp b/libnativeloader/native_loader_test.cpp
index c1dd4aa..878b9f8 100644
--- a/libnativeloader/native_loader_test.cpp
+++ b/libnativeloader/native_loader_test.cpp
@@ -190,6 +190,7 @@
   bool expected_link_with_i18n_ns = true;
   bool expected_link_with_conscrypt_ns = false;
   bool expected_link_with_sphal_ns = !vendor_public_libraries().empty();
+  bool expected_link_with_product_ns = !product_public_libraries().empty();
   bool expected_link_with_vndk_ns = false;
   bool expected_link_with_vndk_product_ns = false;
   bool expected_link_with_default_ns = false;
@@ -199,6 +200,7 @@
   std::string expected_shared_libs_to_i18n_ns = apex_public_libraries().at("com_android_i18n");
   std::string expected_shared_libs_to_conscrypt_ns = apex_jni_libraries("com_android_conscrypt");
   std::string expected_shared_libs_to_sphal_ns = vendor_public_libraries();
+  std::string expected_shared_libs_to_product_ns = product_public_libraries();
   std::string expected_shared_libs_to_vndk_ns = vndksp_libraries_vendor();
   std::string expected_shared_libs_to_vndk_product_ns = vndksp_libraries_product();
   std::string expected_shared_libs_to_default_ns = default_public_libraries();
@@ -237,6 +239,11 @@
                                               StrEq(expected_shared_libs_to_sphal_ns)))
           .WillOnce(Return(true));
     }
+    if (expected_link_with_product_ns) {
+      EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("product"),
+                                              StrEq(expected_shared_libs_to_product_ns)))
+          .WillOnce(Return(true));
+    }
     if (expected_link_with_vndk_ns) {
       EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("vndk"),
                                               StrEq(expected_shared_libs_to_vndk_ns)))
diff --git a/libnativeloader/native_loader_test.h b/libnativeloader/native_loader_test.h
index 09c56e5..5c51f00 100644
--- a/libnativeloader/native_loader_test.h
+++ b/libnativeloader/native_loader_test.h
@@ -87,6 +87,7 @@
 
   NAMESPACE_ENTRY("default"),
   NAMESPACE_ENTRY("sphal"),
+  NAMESPACE_ENTRY("product"),
   NAMESPACE_ENTRY("system"),
   NAMESPACE_ENTRY("vndk"),
   NAMESPACE_ENTRY("vndk_product"),
diff --git a/libnativeloader/public_libraries.cpp b/libnativeloader/public_libraries.cpp
index 9d7124f..5571416 100644
--- a/libnativeloader/public_libraries.cpp
+++ b/libnativeloader/public_libraries.cpp
@@ -55,6 +55,7 @@
 constexpr const char* kExtendedPublicLibrariesFileSuffix = ".txt";
 constexpr const char* kApexLibrariesConfigFile = "/linkerconfig/apex.libraries.config.txt";
 constexpr const char* kVendorPublicLibrariesFile = "/vendor/etc/public.libraries.txt";
+constexpr const char* kProductPublicLibrariesFile = "/product/etc/public.libraries.txt";
 constexpr const char* kLlndkLibrariesFile = "/apex/com.android.vndk.v{}/etc/llndk.libraries.{}.txt";
 constexpr const char* kVndkLibrariesFile = "/apex/com.android.vndk.v{}/etc/vndksp.libraries.{}.txt";
 
@@ -185,6 +186,15 @@
   return android::base::Join(*sonames, ':');
 }
 
+static std::string InitProductPublicLibraries() {
+  // This file is optional, quietly ignore if the file does not exist.
+  auto sonames = ReadConfig(kProductPublicLibrariesFile, always_true);
+  if (!sonames.ok()) {
+    return "";
+  }
+  return android::base::Join(*sonames, ':');
+}
+
 // read /system/etc/public.libraries-<companyname>.txt,
 // /system_ext/etc/public.libraries-<companyname>.txt and
 // /product/etc/public.libraries-<companyname>.txt which contain partner defined
@@ -194,7 +204,9 @@
   std::vector<std::string> sonames;
   ReadExtensionLibraries("/system/etc", &sonames);
   ReadExtensionLibraries("/system_ext/etc", &sonames);
-  ReadExtensionLibraries("/product/etc", &sonames);
+  if (!is_product_vndk_version_defined()) {
+    ReadExtensionLibraries("/product/etc", &sonames);
+  }
   return android::base::Join(sonames, ':');
 }
 
@@ -305,6 +317,11 @@
   return list;
 }
 
+const std::string& product_public_libraries() {
+  static std::string list = InitProductPublicLibraries();
+  return list;
+}
+
 const std::string& extended_public_libraries() {
   static std::string list = InitExtendedPublicLibraries();
   return list;
diff --git a/libnativeloader/public_libraries.h b/libnativeloader/public_libraries.h
index 71c1b8f..6f5a13c 100644
--- a/libnativeloader/public_libraries.h
+++ b/libnativeloader/public_libraries.h
@@ -33,6 +33,7 @@
 const std::string& preloadable_public_libraries();
 const std::string& default_public_libraries();
 const std::string& vendor_public_libraries();
+const std::string& product_public_libraries();
 const std::string& extended_public_libraries();
 const std::string& llndk_libraries_product();
 const std::string& llndk_libraries_vendor();