fs_config: add product and product_services

Mechanical extension of mount directories to also support product/
and product_services/ as individually supplied images.

NB: In the distant past, a prototype placing the make rules into a
    macro was rejected as too difficult to maintain within the macro
    rules, so rules are rolled-out to make them easy to understand.

Test: compile
Bug: 119310326
Change-Id: Ief137cbe62db7175ee02275804ff1d644858dc3d
diff --git a/tools/fs_config/Android.mk b/tools/fs_config/Android.mk
index bf5e171..5ade258 100644
--- a/tools/fs_config/Android.mk
+++ b/tools/fs_config/Android.mk
@@ -104,11 +104,14 @@
 
 include $(BUILD_HOST_EXECUTABLE)
 fs_config_generate_bin := $(LOCAL_INSTALLED_MODULE)
-# List of all supported vendor, oem and odm Partitions
+# List of supported vendor, oem, odm, product and product_services Partitions
 fs_config_generate_extra_partition_list := $(strip \
   $(if $(BOARD_USES_VENDORIMAGE)$(BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE),vendor) \
   $(if $(BOARD_USES_OEMIMAGE)$(BOARD_OEMIMAGE_FILE_SYSTEM_TYPE),oem) \
-  $(if $(BOARD_USES_ODMIMAGE)$(BOARD_ODMIMAGE_FILE_SYSTEM_TYPE),odm))
+  $(if $(BOARD_USES_ODMIMAGE)$(BOARD_ODMIMAGE_FILE_SYSTEM_TYPE),odm) \
+  $(if $(BOARD_PRODUCTIMAGE_FILE_SYSTEM_TYPE),product) \
+  $(if $(BOARD_PRODUCT_SERVICESIMAGE_FILE_SYSTEM_TYPE),product_services) \
+)
 
 ##################################
 # Generate the <p>/etc/fs_config_dirs binary files for each partition.
@@ -286,6 +289,72 @@
 
 endif
 
+ifneq ($(filter product,$(fs_config_generate_extra_partition_list)),)
+##################################
+# Generate the product/etc/fs_config_dirs binary file for the target
+# Add fs_config_dirs or fs_config_dirs_product to PRODUCT_PACKAGES in
+# the device make file to enable
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := fs_config_dirs_product
+LOCAL_MODULE_CLASS := ETC
+LOCAL_INSTALLED_MODULE_STEM := fs_config_dirs
+LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT)/etc
+include $(BUILD_SYSTEM)/base_rules.mk
+$(LOCAL_BUILT_MODULE): $(fs_config_generate_bin)
+	@mkdir -p $(dir $@)
+	$< -D -P product -o $@
+
+##################################
+# Generate the product/etc/fs_config_files binary file for the target
+# Add fs_config_files of fs_config_files_product to PRODUCT_PACKAGES in
+# the device make file to enable
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := fs_config_files_product
+LOCAL_MODULE_CLASS := ETC
+LOCAL_INSTALLED_MODULE_STEM := fs_config_files
+LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT)/etc
+include $(BUILD_SYSTEM)/base_rules.mk
+$(LOCAL_BUILT_MODULE): $(fs_config_generate_bin)
+	@mkdir -p $(dir $@)
+	$< -F -P product -o $@
+
+endif
+
+ifneq ($(filter product_services,$(fs_config_generate_extra_partition_list)),)
+##################################
+# Generate the product_services/etc/fs_config_dirs binary file for the target
+# Add fs_config_dirs or fs_config_dirs_product_services to PRODUCT_PACKAGES in
+# the device make file to enable
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := fs_config_dirs_product_services
+LOCAL_MODULE_CLASS := ETC
+LOCAL_INSTALLED_MODULE_STEM := fs_config_dirs
+LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT_SERVICES)/etc
+include $(BUILD_SYSTEM)/base_rules.mk
+$(LOCAL_BUILT_MODULE): $(fs_config_generate_bin)
+	@mkdir -p $(dir $@)
+	$< -D -P product_services -o $@
+
+##################################
+# Generate the product_services/etc/fs_config_files binary file for the target
+# Add fs_config_files of fs_config_files_product_services to PRODUCT_PACKAGES in
+# the device make file to enable
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := fs_config_files_product_services
+LOCAL_MODULE_CLASS := ETC
+LOCAL_INSTALLED_MODULE_STEM := fs_config_files
+LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT_SERVICES)/etc
+include $(BUILD_SYSTEM)/base_rules.mk
+$(LOCAL_BUILT_MODULE): $(fs_config_generate_bin)
+	@mkdir -p $(dir $@)
+	$< -F -P product_services -o $@
+
+endif
+
 ##################################
 # Build the oemaid header library when fs config files are present.
 # Intentionally break build if you require generated AIDs
diff --git a/tools/fs_config/android_filesystem_config_test_data.h b/tools/fs_config/android_filesystem_config_test_data.h
index 07bc8e5..c65d406 100644
--- a/tools/fs_config/android_filesystem_config_test_data.h
+++ b/tools/fs_config/android_filesystem_config_test_data.h
@@ -26,6 +26,8 @@
     {00555, AID_ROOT, AID_SYSTEM, 0, "vendor/etc"},
     {00555, AID_ROOT, AID_SYSTEM, 0, "oem/etc"},
     {00555, AID_ROOT, AID_SYSTEM, 0, "odm/etc"},
+    {00555, AID_ROOT, AID_SYSTEM, 0, "product/etc"},
+    {00555, AID_ROOT, AID_SYSTEM, 0, "product_services/etc"},
     {00755, AID_SYSTEM, AID_ROOT, 0, "system/oem/etc"},
     {00755, AID_SYSTEM, AID_ROOT, 0, "system/odm/etc"},
     {00755, AID_SYSTEM, AID_ROOT, 0, "system/vendor/etc"},
@@ -41,16 +43,22 @@
     {00444, AID_ROOT, AID_SYSTEM, 0, "vendor/etc/fs_config_dirs"},
     {00444, AID_ROOT, AID_SYSTEM, 0, "oem/etc/fs_config_dirs"},
     {00444, AID_ROOT, AID_SYSTEM, 0, "odm/etc/fs_config_dirs"},
+    {00444, AID_ROOT, AID_SYSTEM, 0, "product/etc/fs_config_dirs"},
+    {00444, AID_ROOT, AID_SYSTEM, 0, "product_services/etc/fs_config_dirs"},
     {00444, AID_ROOT, AID_SYSTEM, 0, "system/etc/fs_config_files"},
     {00444, AID_ROOT, AID_SYSTEM, 0, "vendor/etc/fs_config_files"},
     {00444, AID_ROOT, AID_SYSTEM, 0, "oem/etc/fs_config_files"},
     {00444, AID_ROOT, AID_SYSTEM, 0, "odm/etc/fs_config_files"},
+    {00444, AID_ROOT, AID_SYSTEM, 0, "product/etc/fs_config_files"},
+    {00444, AID_ROOT, AID_SYSTEM, 0, "product_services/etc/fs_config_files"},
     {00644, AID_SYSTEM, AID_ROOT, 0, "system/vendor/etc/fs_config_dirs"},
     {00644, AID_SYSTEM, AID_ROOT, 0, "system/oem/etc/fs_config_dirs"},
     {00644, AID_SYSTEM, AID_ROOT, 0, "system/odm/etc/fs_config_dirs"},
     {00644, AID_SYSTEM, AID_ROOT, 0, "system/vendor/etc/fs_config_files"},
     {00644, AID_SYSTEM, AID_ROOT, 0, "system/oem/etc/fs_config_files"},
     {00644, AID_SYSTEM, AID_ROOT, 0, "system/odm/etc/fs_config_files"},
+    {00644, AID_SYSTEM, AID_ROOT, 0, "system/product/etc/fs_config_files"},
+    {00644, AID_SYSTEM, AID_ROOT, 0, "system/product_services/etc/fs_config_files"},
     {00644, AID_SYSTEM, AID_ROOT, 0, "etc/fs_config_files"},
     {00666, AID_ROOT, AID_SYSTEM, 0, "data/misc/oem"},
 };
diff --git a/tools/fs_config/fs_config_generate.c b/tools/fs_config/fs_config_generate.c
index cb7ff9d..0f0603b 100644
--- a/tools/fs_config/fs_config_generate.c
+++ b/tools/fs_config/fs_config_generate.c
@@ -47,11 +47,15 @@
     {0000, AID_ROOT, AID_ROOT, 0, "vendor/etc/fs_config_dirs"},
     {0000, AID_ROOT, AID_ROOT, 0, "oem/etc/fs_config_dirs"},
     {0000, AID_ROOT, AID_ROOT, 0, "odm/etc/fs_config_dirs"},
+    {0000, AID_ROOT, AID_ROOT, 0, "product/etc/fs_config_dirs"},
+    {0000, AID_ROOT, AID_ROOT, 0, "product_services/etc/fs_config_dirs"},
 #endif
     {0000, AID_ROOT, AID_ROOT, 0, "system/etc/fs_config_files"},
     {0000, AID_ROOT, AID_ROOT, 0, "vendor/etc/fs_config_files"},
     {0000, AID_ROOT, AID_ROOT, 0, "oem/etc/fs_config_files"},
     {0000, AID_ROOT, AID_ROOT, 0, "odm/etc/fs_config_files"},
+    {0000, AID_ROOT, AID_ROOT, 0, "product/etc/fs_config_files"},
+    {0000, AID_ROOT, AID_ROOT, 0, "product_services/etc/fs_config_files"},
 };
 #endif
 
diff --git a/tools/fs_config/fs_config_test.cpp b/tools/fs_config/fs_config_test.cpp
index f95a4ca..916c615 100644
--- a/tools/fs_config/fs_config_test.cpp
+++ b/tools/fs_config/fs_config_test.cpp
@@ -23,7 +23,6 @@
 #include <android-base/file.h>
 #include <android-base/macros.h>
 #include <android-base/strings.h>
-#include <android-base/stringprintf.h>
 #include <gtest/gtest.h>
 #include <private/android_filesystem_config.h>
 #include <private/fs_config.h>
@@ -31,12 +30,12 @@
 #include "android_filesystem_config_test_data.h"
 
 // must run test in the test directory
-const static char fs_config_generate_command[] = "./fs_config_generate_test";
+static const std::string fs_config_generate_command = "./fs_config_generate_test";
 
-static std::string popenToString(std::string command) {
+static std::string popenToString(const std::string command) {
   std::string ret;
 
-  FILE* fp = popen(command.c_str(), "r");
+  auto fp = popen(command.c_str(), "r");
   if (fp) {
     if (!android::base::ReadFdToString(fileno(fp), &ret)) ret = "";
     pclose(fp);
@@ -46,15 +45,14 @@
 
 static void confirm(std::string&& data, const fs_path_config* config,
                     ssize_t num_config) {
-  const struct fs_path_config_from_file* pc =
-      reinterpret_cast<const fs_path_config_from_file*>(data.c_str());
-  size_t len = data.size();
+  auto pc = reinterpret_cast<const fs_path_config_from_file*>(data.c_str());
+  auto len = data.size();
 
   ASSERT_TRUE(config != NULL);
   ASSERT_LT(0, num_config);
 
   while (len > 0) {
-    uint16_t host_len = pc->len;
+    auto host_len = pc->len;
     if (host_len > len) break;
 
     EXPECT_EQ(config->mode, pc->mode);
@@ -76,148 +74,114 @@
 /* See local android_filesystem_config.h for test data */
 
 TEST(fs_conf_test, dirs) {
-  confirm(popenToString(
-              android::base::StringPrintf("%s -D", fs_config_generate_command)),
+  confirm(popenToString(fs_config_generate_command + " -D"),
           android_device_dirs, arraysize(android_device_dirs));
 }
 
 TEST(fs_conf_test, files) {
-  confirm(popenToString(
-              android::base::StringPrintf("%s -F", fs_config_generate_command)),
+  confirm(popenToString(fs_config_generate_command + " -F"),
           android_device_files, arraysize(android_device_files));
 }
 
-static const char vendor_str[] = "vendor/";
-static const char vendor_alt_str[] = "system/vendor/";
-static const char oem_str[] = "oem/";
-static const char oem_alt_str[] = "system/oem/";
-static const char odm_str[] = "odm/";
-static const char odm_alt_str[] = "system/odm/";
+static bool is_system(const char* prefix) {
+  return !android::base::StartsWith(prefix, "vendor/") &&
+         !android::base::StartsWith(prefix, "system/vendor/") &&
+         !android::base::StartsWith(prefix, "oem/") &&
+         !android::base::StartsWith(prefix, "system/oem/") &&
+         !android::base::StartsWith(prefix, "odm/") &&
+         !android::base::StartsWith(prefix, "system/odm/") &&
+         !android::base::StartsWith(prefix, "product/") &&
+         !android::base::StartsWith(prefix, "system/product/") &&
+         !android::base::StartsWith(prefix, "product_services/") &&
+         !android::base::StartsWith(prefix, "system/product_services/");
+}
 
 TEST(fs_conf_test, system_dirs) {
   std::vector<fs_path_config> dirs;
-  const fs_path_config* config = android_device_dirs;
-  for (size_t num = arraysize(android_device_dirs); num; --num) {
-    if (!android::base::StartsWith(config->prefix, vendor_str) &&
-        !android::base::StartsWith(config->prefix, vendor_alt_str) &&
-        !android::base::StartsWith(config->prefix, oem_str) &&
-        !android::base::StartsWith(config->prefix, oem_alt_str) &&
-        !android::base::StartsWith(config->prefix, odm_str) &&
-        !android::base::StartsWith(config->prefix, odm_alt_str)) {
+  auto config = android_device_dirs;
+  for (auto num = arraysize(android_device_dirs); num; --num) {
+    if (is_system(config->prefix)) {
       dirs.emplace_back(*config);
     }
     ++config;
   }
-  confirm(popenToString(android::base::StringPrintf(
-              "%s -D -P -vendor,-oem,-odm", fs_config_generate_command)),
+  confirm(popenToString(fs_config_generate_command + " -D -P -vendor,-oem,-odm,-product,-product_services"),
+          &dirs[0], dirs.size());
+}
+
+static void fs_conf_test_dirs(const std::string& partition_name) {
+  std::vector<fs_path_config> dirs;
+  auto config = android_device_dirs;
+  const auto str = partition_name + "/";
+  const auto alt_str = "system/" + partition_name + "/";
+  for (auto num = arraysize(android_device_dirs); num; --num) {
+    if (android::base::StartsWith(config->prefix, str) ||
+        android::base::StartsWith(config->prefix, alt_str)) {
+      dirs.emplace_back(*config);
+    }
+    ++config;
+  }
+  confirm(popenToString(fs_config_generate_command + " -D -P " + partition_name),
           &dirs[0], dirs.size());
 }
 
 TEST(fs_conf_test, vendor_dirs) {
-  std::vector<fs_path_config> dirs;
-  const fs_path_config* config = android_device_dirs;
-  for (size_t num = arraysize(android_device_dirs); num; --num) {
-    if (android::base::StartsWith(config->prefix, vendor_str) ||
-        android::base::StartsWith(config->prefix, vendor_alt_str)) {
-      dirs.emplace_back(*config);
-    }
-    ++config;
-  }
-  confirm(popenToString(android::base::StringPrintf(
-              "%s -D -P vendor", fs_config_generate_command)),
-          &dirs[0], dirs.size());
+  fs_conf_test_dirs("vendor");
 }
 
 TEST(fs_conf_test, oem_dirs) {
-  std::vector<fs_path_config> dirs;
-  const fs_path_config* config = android_device_dirs;
-  for (size_t num = arraysize(android_device_dirs); num; --num) {
-    if (android::base::StartsWith(config->prefix, oem_str) ||
-        android::base::StartsWith(config->prefix, oem_alt_str)) {
-      dirs.emplace_back(*config);
-    }
-    ++config;
-  }
-  confirm(popenToString(android::base::StringPrintf(
-              "%s -D -P oem", fs_config_generate_command)),
-          &dirs[0], dirs.size());
+  fs_conf_test_dirs("oem");
 }
 
 TEST(fs_conf_test, odm_dirs) {
-  std::vector<fs_path_config> dirs;
-  const fs_path_config* config = android_device_dirs;
-  for (size_t num = arraysize(android_device_dirs); num; --num) {
-    if (android::base::StartsWith(config->prefix, odm_str) ||
-        android::base::StartsWith(config->prefix, odm_alt_str)) {
-      dirs.emplace_back(*config);
-    }
-    ++config;
-  }
-  confirm(popenToString(android::base::StringPrintf(
-              "%s -D -P odm", fs_config_generate_command)),
-          &dirs[0], dirs.size());
+  fs_conf_test_dirs("odm");
 }
 
 TEST(fs_conf_test, system_files) {
   std::vector<fs_path_config> files;
-  const fs_path_config* config = android_device_files;
-  for (size_t num = arraysize(android_device_files); num; --num) {
-    if (!android::base::StartsWith(config->prefix, vendor_str) &&
-        !android::base::StartsWith(config->prefix, vendor_alt_str) &&
-        !android::base::StartsWith(config->prefix, oem_str) &&
-        !android::base::StartsWith(config->prefix, oem_alt_str) &&
-        !android::base::StartsWith(config->prefix, odm_str) &&
-        !android::base::StartsWith(config->prefix, odm_alt_str)) {
+  auto config = android_device_files;
+  for (auto num = arraysize(android_device_files); num; --num) {
+    if (is_system(config->prefix)) {
       files.emplace_back(*config);
     }
     ++config;
   }
-  confirm(popenToString(android::base::StringPrintf(
-              "%s -F -P -vendor,-oem,-odm", fs_config_generate_command)),
+  confirm(popenToString(fs_config_generate_command + " -F -P -vendor,-oem,-odm,-product,-product_services"),
+          &files[0], files.size());
+}
+
+static void fs_conf_test_files(const std::string& partition_name) {
+  std::vector<fs_path_config> files;
+  auto config = android_device_files;
+  const auto str = partition_name + "/";
+  const auto alt_str = "system/" + partition_name + "/";
+  for (auto num = arraysize(android_device_files); num; --num) {
+    if (android::base::StartsWith(config->prefix, str) ||
+        android::base::StartsWith(config->prefix, alt_str)) {
+      files.emplace_back(*config);
+    }
+    ++config;
+  }
+  confirm(popenToString(fs_config_generate_command + " -F -P " + partition_name),
           &files[0], files.size());
 }
 
 TEST(fs_conf_test, vendor_files) {
-  std::vector<fs_path_config> files;
-  const fs_path_config* config = android_device_files;
-  for (size_t num = arraysize(android_device_files); num; --num) {
-    if (android::base::StartsWith(config->prefix, vendor_str) ||
-        android::base::StartsWith(config->prefix, vendor_alt_str)) {
-      files.emplace_back(*config);
-    }
-    ++config;
-  }
-  confirm(popenToString(android::base::StringPrintf(
-              "%s -F -P vendor", fs_config_generate_command)),
-          &files[0], files.size());
+  fs_conf_test_files("vendor");
 }
 
 TEST(fs_conf_test, oem_files) {
-  std::vector<fs_path_config> files;
-  const fs_path_config* config = android_device_files;
-  for (size_t num = arraysize(android_device_files); num; --num) {
-    if (android::base::StartsWith(config->prefix, oem_str) ||
-        android::base::StartsWith(config->prefix, oem_alt_str)) {
-      files.emplace_back(*config);
-    }
-    ++config;
-  }
-  confirm(popenToString(android::base::StringPrintf(
-              "%s -F -P oem", fs_config_generate_command)),
-          &files[0], files.size());
+  fs_conf_test_files("oem");
 }
 
 TEST(fs_conf_test, odm_files) {
-  std::vector<fs_path_config> files;
-  const fs_path_config* config = android_device_files;
-  for (size_t num = arraysize(android_device_files); num; --num) {
-    if (android::base::StartsWith(config->prefix, odm_str) ||
-        android::base::StartsWith(config->prefix, odm_alt_str)) {
-      files.emplace_back(*config);
-    }
-    ++config;
-  }
-  confirm(popenToString(android::base::StringPrintf(
-              "%s -F -P odm", fs_config_generate_command)),
-          &files[0], files.size());
+  fs_conf_test_files("odm");
+}
+
+TEST(fs_conf_test, product_files) {
+  fs_conf_test_files("product");
+}
+
+TEST(fs_conf_test, product_services_files) {
+  fs_conf_test_files("product_services");
 }