Load boot image props.

This change does the following:

- Create /second_stage_resources empty dir at root.
- At runtime:
  - At first stage init:
    - mount tmpfs to /second_stage_resources.
    - Copy /system/etc/ramdisk/build.prop to
      /second_stage_resources/system/etc/ramdisk/build.prop
  - At second stage init:
    - Load prop from the above path
    - umount /second_stage_resources

Test: getprop -Z
Test: getprop
Bug: 169169031

Change-Id: I18b16aa5fd42fa44686c858982a17791b2d43489
diff --git a/init/Android.mk b/init/Android.mk
index da94daf..7d7c827 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -80,6 +80,7 @@
     $(TARGET_RAMDISK_OUT)/dev \
     $(TARGET_RAMDISK_OUT)/mnt \
     $(TARGET_RAMDISK_OUT)/proc \
+    $(TARGET_RAMDISK_OUT)/second_stage_resources \
     $(TARGET_RAMDISK_OUT)/sys \
 
 LOCAL_STATIC_LIBRARIES := \
diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp
index 0215576..554f301 100644
--- a/init/first_stage_init.cpp
+++ b/init/first_stage_init.cpp
@@ -41,6 +41,7 @@
 #include "first_stage_console.h"
 #include "first_stage_mount.h"
 #include "reboot_utils.h"
+#include "second_stage_resources.h"
 #include "switch_root.h"
 #include "util.h"
 
@@ -235,6 +236,11 @@
     // /debug_ramdisk is used to preserve additional files from the debug ramdisk
     CHECKCALL(mount("tmpfs", "/debug_ramdisk", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
                     "mode=0755,uid=0,gid=0"));
+
+    // /second_stage_resources is used to preserve files from first to second
+    // stage init
+    CHECKCALL(mount("tmpfs", kSecondStageRes, "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
+                    "mode=0755,uid=0,gid=0"))
 #undef CHECKCALL
 
     SetStdioToDevNull(argv);
@@ -276,6 +282,20 @@
         StartConsole();
     }
 
+    if (access(kBootImageRamdiskProp, F_OK) == 0) {
+        std::string dest = GetRamdiskPropForSecondStage();
+        std::string dir = android::base::Dirname(dest);
+        std::error_code ec;
+        if (!fs::create_directories(dir, ec)) {
+            LOG(FATAL) << "Can't mkdir " << dir << ": " << ec.message();
+        }
+        if (!fs::copy_file(kBootImageRamdiskProp, dest, ec)) {
+            LOG(FATAL) << "Can't copy " << kBootImageRamdiskProp << " to " << dest << ": "
+                       << ec.message();
+        }
+        LOG(INFO) << "Copied ramdisk prop to " << dest;
+    }
+
     if (ForceNormalBoot(cmdline)) {
         mkdir("/first_stage_ramdisk", 0755);
         // SwitchRoot() must be called with a mount point as the target, so we bind mount the
diff --git a/init/init.cpp b/init/init.cpp
index 7d00538..ea04494 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -71,6 +71,7 @@
 #include "proto_utils.h"
 #include "reboot.h"
 #include "reboot_utils.h"
+#include "second_stage_resources.h"
 #include "security.h"
 #include "selabel.h"
 #include "selinux.h"
@@ -668,6 +669,12 @@
     }
 }
 
+static void UmountSecondStageRes() {
+    if (umount(kSecondStageRes) != 0) {
+        PLOG(ERROR) << "Failed to umount " << kSecondStageRes;
+    }
+}
+
 static void MountExtraFilesystems() {
 #define CHECKCALL(x) \
     if ((x) != 0) PLOG(FATAL) << #x " failed.";
@@ -776,6 +783,9 @@
 
     PropertyInit();
 
+    // Umount second stage resources after property service has read the .prop files.
+    UmountSecondStageRes();
+
     // Umount the debug ramdisk after property service has read the .prop files when it means to.
     if (load_debug_prop) {
         UmountDebugRamdisk();
diff --git a/init/property_service.cpp b/init/property_service.cpp
index a1e0969..e4c9802 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -67,6 +67,7 @@
 #include "persistent_properties.h"
 #include "property_type.h"
 #include "proto_utils.h"
+#include "second_stage_resources.h"
 #include "selinux.h"
 #include "subcontext.h"
 #include "system/core/init/property_service.pb.h"
@@ -745,6 +746,15 @@
     return true;
 }
 
+static void LoadPropertiesFromSecondStageRes(std::map<std::string, std::string>* properties) {
+    std::string prop = GetRamdiskPropForSecondStage();
+    if (access(prop.c_str(), R_OK) != 0) {
+        CHECK(errno == ENOENT) << "Cannot access " << prop << ": " << strerror(errno);
+        return;
+    }
+    load_properties_from_file(prop.c_str(), nullptr, properties);
+}
+
 // persist.sys.usb.config values can't be combined on build-time when property
 // files are split into each partition.
 // So we need to apply the same rule of build/make/tools/post_process_props.py
@@ -933,6 +943,7 @@
 
     // Order matters here. The more the partition is specific to a product, the higher its
     // precedence is.
+    LoadPropertiesFromSecondStageRes(&properties);
     load_properties_from_file("/system/build.prop", nullptr, &properties);
     load_properties_from_partition("system_ext", /* support_legacy_path_until */ 30);
     // TODO(b/117892318): uncomment the following condition when vendor.imgs for aosp_* targets are
diff --git a/init/second_stage_resources.h b/init/second_stage_resources.h
new file mode 100644
index 0000000..544d16f
--- /dev/null
+++ b/init/second_stage_resources.h
@@ -0,0 +1,32 @@
+/*
+ * 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 init {
+
+constexpr const char kSecondStageRes[] = "/second_stage_resources";
+constexpr const char kBootImageRamdiskProp[] = "/system/etc/ramdisk/build.prop";
+
+inline std::string GetRamdiskPropForSecondStage() {
+    return std::string(kSecondStageRes) + kBootImageRamdiskProp;
+}
+
+}  // namespace init
+}  // namespace android
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 77fa94e..2bceb75 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -78,7 +78,7 @@
 # create some directories (some are mount points) and symlinks
 LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
     dev proc sys system data data_mirror odm oem acct config storage mnt apex debug_ramdisk \
-    linkerconfig $(BOARD_ROOT_EXTRA_FOLDERS)); \
+    linkerconfig second_stage_resources $(BOARD_ROOT_EXTRA_FOLDERS)); \
     ln -sf /system/bin $(TARGET_ROOT_OUT)/bin; \
     ln -sf /system/etc $(TARGET_ROOT_OUT)/etc; \
     ln -sf /data/user_de/0/com.android.shell/files/bugreports $(TARGET_ROOT_OUT)/bugreports; \