Merge "Read apex_manifest and generate Namespace" am: 5fa6e715d4
am: 6e04984957

Change-Id: I57477b4fa730f95ed45dbf43f42efe69951ee86e
diff --git a/Android.bp b/Android.bp
index bf980cd..c93ea50 100644
--- a/Android.bp
+++ b/Android.bp
@@ -24,6 +24,8 @@
     static_libs: [
         "libbase",
         "liblog",
+        "libprotobuf-cpp-lite",
+        "lib_apex_manifest_proto_lite",
     ],
     host_supported: true,
     recovery_available: true,
@@ -100,6 +102,7 @@
         "modules/tests/*_test.cc",
     ],
     static_libs: [
+        "libgmock",
         "linkerconfig_modules",
     ],
 }
diff --git a/contents/tests/configuration/vndk_test.cc b/contents/tests/configuration/vndk_test.cc
index 495c42d..81d4b98 100644
--- a/contents/tests/configuration/vndk_test.cc
+++ b/contents/tests/configuration/vndk_test.cc
@@ -20,13 +20,13 @@
 #include <unordered_map>
 #include <vector>
 
+#include <gtest/gtest.h>
+
 #include "linkerconfig/context.h"
 #include "linkerconfig/namespace.h"
 #include "linkerconfig/namespacebuilder.h"
 #include "linkerconfig/sectionbuilder.h"
 
-#include "gtest/gtest.h"
-
 using namespace android::linkerconfig::contents;
 using namespace android::linkerconfig::modules;
 
diff --git a/modules/include/linkerconfig/link.h b/modules/include/linkerconfig/link.h
index 860e943..3208494 100644
--- a/modules/include/linkerconfig/link.h
+++ b/modules/include/linkerconfig/link.h
@@ -41,6 +41,10 @@
   void AllowAllSharedLibs();
   void WriteConfig(ConfigWriter& writer) const;
 
+  // accessors
+  std::vector<std::string> GetSharedLibs() const {
+    return shared_libs_;
+  }
   std::string To() const {
     return target_namespace_;
   }
diff --git a/modules/include/linkerconfig/namespace.h b/modules/include/linkerconfig/namespace.h
index 64c69c8..1cc6a6b 100644
--- a/modules/include/linkerconfig/namespace.h
+++ b/modules/include/linkerconfig/namespace.h
@@ -19,6 +19,8 @@
 #include <string>
 #include <vector>
 
+#include <android-base/result.h>
+
 #include "linkerconfig/configwriter.h"
 #include "linkerconfig/link.h"
 #include "linkerconfig/log.h"
@@ -109,10 +111,20 @@
   bool ContainsSearchPath(const std::string& path, AsanPath path_from_asan);
   bool ContainsPermittedPath(const std::string& path, AsanPath path_from_asan);
 
-  void AddProvides(std::vector<std::string> list);
-  void AddRequires(std::vector<std::string> list);
-  const std::set<std::string>& GetProvides() const;
-  const std::set<std::string>& GetRequires() const;
+  template <typename Vec>
+  void AddProvides(const Vec& list) {
+    provides_.insert(list.begin(), list.end());
+  }
+  template <typename Vec>
+  void AddRequires(const Vec& list) {
+    requires_.insert(list.begin(), list.end());
+  }
+  const std::set<std::string>& GetProvides() const {
+    return provides_;
+  }
+  const std::set<std::string>& GetRequires() const {
+    return requires_;
+  }
 
  private:
   const bool is_isolated_;
@@ -130,6 +142,10 @@
   void WritePathString(ConfigWriter& writer, const std::string& path_type,
                        const std::vector<std::string>& path_list);
 };
+
+::android::base::Result<void> InitializeWithApex(Namespace& ns,
+                                                 const std::string& apex_path);
+
 }  // namespace modules
 }  // namespace linkerconfig
 }  // namespace android
diff --git a/modules/include/linkerconfig/section.h b/modules/include/linkerconfig/section.h
index c945fa2..7f2c4a1 100644
--- a/modules/include/linkerconfig/section.h
+++ b/modules/include/linkerconfig/section.h
@@ -20,7 +20,8 @@
 #include <utility>
 #include <vector>
 
-#include "android-base/result.h"
+#include <android-base/result.h>
+
 #include "linkerconfig/configwriter.h"
 #include "linkerconfig/namespace.h"
 
diff --git a/modules/namespace.cc b/modules/namespace.cc
index 3a36ee1..bdc45d5 100644
--- a/modules/namespace.cc
+++ b/modules/namespace.cc
@@ -16,11 +16,22 @@
 
 #include "linkerconfig/namespace.h"
 
+#include <android-base/file.h>
 #include <android-base/strings.h>
+#include <apex_manifest.pb.h>
 
 #include "linkerconfig/log.h"
 
+using ::android::base::Error;
+using ::android::base::ReadFileToString;
+using ::android::base::Result;
+using ::android::base::WriteStringToFile;
+using ::apex::proto::ApexManifest;
+
 namespace {
+
+constexpr const char* kDataAsanPath = "/data/asan";
+
 bool FindFromPathList(const std::vector<std::string>& list,
                       const std::string& path) {
   for (auto& path_member : list) {
@@ -31,13 +42,37 @@
 
   return false;
 }
+
+Result<ApexManifest> ParseApexManifest(const std::string& manifest_path) {
+  std::string content;
+  if (!ReadFileToString(manifest_path, &content)) {
+    return Error() << "Failed to read manifest file: " << manifest_path;
+  }
+
+  ApexManifest manifest;
+  if (!manifest.ParseFromString(content)) {
+    return Error() << "Can't parse APEX manifest.";
+  }
+  return manifest;
+}
+
 }  // namespace
 
 namespace android {
 namespace linkerconfig {
 namespace modules {
 
-constexpr const char* kDataAsanPath = "/data/asan";
+Result<void> InitializeWithApex(Namespace& ns, const std::string& apex_path) {
+  auto apex_manifest = ParseApexManifest(apex_path + "/apex_manifest.pb");
+  if (!apex_manifest) {
+    return apex_manifest.error();
+  }
+  ns.AddSearchPath(apex_path + "/${LIB}");
+  ns.AddPermittedPath("/system/${LIB}");
+  ns.AddProvides(apex_manifest->providenativelibs());
+  ns.AddRequires(apex_manifest->requirenativelibs());
+  return {};
+}
 
 void Namespace::WritePathString(ConfigWriter& writer,
                                 const std::string& path_type,
@@ -155,21 +190,6 @@
           FindFromPathList(asan_permitted_paths_, kDataAsanPath + path));
 }
 
-void Namespace::AddProvides(std::vector<std::string> list) {
-  provides_.insert(list.begin(), list.end());
-}
-
-void Namespace::AddRequires(std::vector<std::string> list) {
-  requires_.insert(list.begin(), list.end());
-}
-
-const std::set<std::string>& Namespace::GetProvides() const {
-  return provides_;
-}
-
-const std::set<std::string>& Namespace::GetRequires() const {
-  return requires_;
-}
 }  // namespace modules
 }  // namespace linkerconfig
 }  // namespace android
diff --git a/modules/section.cc b/modules/section.cc
index 16ad7fb..b4e66f1 100644
--- a/modules/section.cc
+++ b/modules/section.cc
@@ -18,7 +18,7 @@
 
 #include <unordered_map>
 
-#include "android-base/result.h"
+#include <android-base/result.h>
 
 using android::base::Errorf;
 using android::base::Result;
diff --git a/modules/tests/apex_test.cc b/modules/tests/apex_test.cc
new file mode 100644
index 0000000..72923a5
--- /dev/null
+++ b/modules/tests/apex_test.cc
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2019 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 <string>
+#include <utility>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/result.h>
+#include <android-base/stringprintf.h>
+#include <apex_manifest.pb.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "linkerconfig/configwriter.h"
+#include "linkerconfig/namespace.h"
+#include "linkerconfig/section.h"
+
+using ::android::base::Result;
+using ::android::base::StringPrintf;
+using ::android::base::WriteStringToFile;
+using ::android::linkerconfig::modules::ConfigWriter;
+using ::android::linkerconfig::modules::InitializeWithApex;
+using ::android::linkerconfig::modules::Namespace;
+using ::android::linkerconfig::modules::Section;
+using ::apex::proto::ApexManifest;
+using ::testing::Contains;
+
+namespace {
+
+void PrepareTestApexDir(const std::string& path, const std::string& name,
+                        std::vector<std::string> provided_libs,
+                        std::vector<std::string> required_libs) {
+  ApexManifest manifest;
+  manifest.set_name(name);
+  for (auto lib : provided_libs) {
+    manifest.add_providenativelibs(lib);
+  }
+  for (auto lib : required_libs) {
+    manifest.add_requirenativelibs(lib);
+  }
+  std::string content = manifest.SerializeAsString();
+  std::string manifest_path = path + "/apex_manifest.pb";
+  if (!WriteStringToFile(content, manifest_path)) {
+    LOG(ERROR) << "Failed to write a file: " << manifest_path;
+  }
+}
+
+}  // namespace
+
+TEST(apex_namespace, build_namespace) {
+  TemporaryDir foo_dir;
+  PrepareTestApexDir(foo_dir.path, "foo", {}, {});
+
+  Namespace ns("foo");
+  auto result = InitializeWithApex(ns, foo_dir.path);
+  ASSERT_TRUE(result);
+
+  ConfigWriter writer;
+  ns.WriteConfig(writer);
+  ASSERT_EQ(
+      StringPrintf("namespace.foo.isolated = false\n"
+                   "namespace.foo.search.paths = %s/${LIB}\n"
+                   "namespace.foo.permitted.paths = /system/${LIB}\n"
+                   "namespace.foo.asan.search.paths = %s/${LIB}\n"
+                   "namespace.foo.asan.permitted.paths = /system/${LIB}\n",
+                   foo_dir.path,
+                   foo_dir.path),
+      writer.ToString());
+}
+
+TEST(apex_namespace, resolve_between_apex_namespaces) {
+  TemporaryDir foo_dir, bar_dir;
+  PrepareTestApexDir(foo_dir.path, "foo", {"foo.so"}, {"bar.so"});
+  PrepareTestApexDir(bar_dir.path, "bar", {"bar.so"}, {});
+
+  Namespace foo("foo"), bar("bar");
+  InitializeWithApex(foo, foo_dir.path);
+  InitializeWithApex(bar, bar_dir.path);
+
+  std::vector<Namespace> namespaces;
+  namespaces.push_back(std::move(foo));
+  namespaces.push_back(std::move(bar));
+  Section section("section", std::move(namespaces));
+
+  auto result = section.Resolve();
+  ASSERT_TRUE(result) << result.error();
+
+  // See if two namespaces are linked correctly
+  ASSERT_THAT(section.GetNamespace("foo")->GetLink("bar").GetSharedLibs(),
+              Contains("bar.so"));
+}
\ No newline at end of file
diff --git a/modules/tests/section_test.cc b/modules/tests/section_test.cc
index ef6cdba..8a5253e 100644
--- a/modules/tests/section_test.cc
+++ b/modules/tests/section_test.cc
@@ -14,11 +14,12 @@
  * limitations under the License.
  */
 
+#include "linkerconfig/section.h"
+
+#include <android-base/result.h>
 #include <gtest/gtest.h>
 
-#include "android-base/result.h"
 #include "linkerconfig/configwriter.h"
-#include "linkerconfig/section.h"
 #include "modules_testbase.h"
 
 using android::base::Errorf;
@@ -129,12 +130,12 @@
 TEST(linkerconfig_section, resolve_contraints) {
   std::vector<Namespace> namespaces;
   Namespace& foo = namespaces.emplace_back("foo");
-  foo.AddProvides({"libfoo.so"});
-  foo.AddRequires({"libbar.so"});
+  foo.AddProvides(std::vector{"libfoo.so"});
+  foo.AddRequires(std::vector{"libbar.so"});
   Namespace& bar = namespaces.emplace_back("bar");
-  bar.AddProvides({"libbar.so"});
+  bar.AddProvides(std::vector{"libbar.so"});
   Namespace& baz = namespaces.emplace_back("baz");
-  baz.AddRequires({"libfoo.so"});
+  baz.AddRequires(std::vector{"libfoo.so"});
 
   Section section("section", std::move(namespaces));
   section.Resolve();
@@ -158,11 +159,11 @@
 TEST(linkerconfig_section, error_if_duplicate_providing) {
   std::vector<Namespace> namespaces;
   Namespace& foo1 = namespaces.emplace_back("foo1");
-  foo1.AddProvides({"libfoo.so"});
+  foo1.AddProvides(std::vector{"libfoo.so"});
   Namespace& foo2 = namespaces.emplace_back("foo2");
-  foo2.AddProvides({"libfoo.so"});
+  foo2.AddProvides(std::vector{"libfoo.so"});
   Namespace& bar = namespaces.emplace_back("bar");
-  bar.AddRequires({"libfoo.so"});
+  bar.AddRequires(std::vector{"libfoo.so"});
 
   Section section("section", std::move(namespaces));
   auto result = section.Resolve();
@@ -173,7 +174,7 @@
 TEST(linkerconfig_section, error_if_no_providers) {
   std::vector<Namespace> namespaces;
   Namespace& foo = namespaces.emplace_back("foo");
-  foo.AddRequires({"libfoo.so"});
+  foo.AddRequires(std::vector{"libfoo.so"});
 
   Section section("section", std::move(namespaces));
   auto result = section.Resolve();