Merge "liblog: add a test for liblog on host"
diff --git a/fs_mgr/libfs_avb/Android.bp b/fs_mgr/libfs_avb/Android.bp
index 32702ae..bf51fe7 100644
--- a/fs_mgr/libfs_avb/Android.bp
+++ b/fs_mgr/libfs_avb/Android.bp
@@ -37,11 +37,9 @@
         "libfstab",
     ],
     shared_libs: [
+        "libbase",
         "libcrypto",
     ],
-    header_libs: [
-        "libbase_headers",
-    ],
     target: {
         darwin: {
             enabled: false,
diff --git a/fs_mgr/libfs_avb/fs_avb.cpp b/fs_mgr/libfs_avb/fs_avb.cpp
index c4d7511..8770a6b 100644
--- a/fs_mgr/libfs_avb/fs_avb.cpp
+++ b/fs_mgr/libfs_avb/fs_avb.cpp
@@ -22,6 +22,7 @@
 #include <sys/ioctl.h>
 #include <sys/types.h>
 
+#include <algorithm>
 #include <sstream>
 #include <string>
 #include <vector>
@@ -308,7 +309,18 @@
             return nullptr;
     }
 
-    if (!ValidatePublicKeyBlob(public_key_data, Split(fstab_entry.avb_keys, ":"))) {
+    // fstab_entry.avb_keys might be either a directory containing multiple keys,
+    // or a string indicating multiple keys separated by ':'.
+    std::vector<std::string> allowed_avb_keys;
+    auto list_avb_keys_in_dir = ListFiles(fstab_entry.avb_keys);
+    if (list_avb_keys_in_dir) {
+        std::sort(list_avb_keys_in_dir->begin(), list_avb_keys_in_dir->end());
+        allowed_avb_keys = *list_avb_keys_in_dir;
+    } else {
+        allowed_avb_keys = Split(fstab_entry.avb_keys, ":");
+    }
+
+    if (!ValidatePublicKeyBlob(public_key_data, allowed_avb_keys)) {
         avb_handle->status_ = AvbHandleStatus::kVerificationError;
         LWARNING << "Found unknown public key used to sign " << fstab_entry.mount_point;
         if (!allow_verification_error) {
diff --git a/fs_mgr/libfs_avb/tests/util_test.cpp b/fs_mgr/libfs_avb/tests/util_test.cpp
index 12b5acb..e64282b 100644
--- a/fs_mgr/libfs_avb/tests/util_test.cpp
+++ b/fs_mgr/libfs_avb/tests/util_test.cpp
@@ -16,10 +16,12 @@
 
 #include <unistd.h>
 
+#include <algorithm>
 #include <future>
 #include <string>
 #include <thread>
 
+#include <android-base/strings.h>
 #include <base/files/file_util.h>
 
 #include "fs_avb_test_util.h"
@@ -29,6 +31,7 @@
 using android::fs_mgr::BytesToHex;
 using android::fs_mgr::FileWaitMode;
 using android::fs_mgr::HexToBytes;
+using android::fs_mgr::ListFiles;
 using android::fs_mgr::NibbleValue;
 using android::fs_mgr::WaitForFile;
 
@@ -210,4 +213,102 @@
     ASSERT_TRUE(base::DeleteFile(wait_path, false /* resursive */));
 }
 
+TEST(BasicUtilTest, ListFiles) {
+    // Gets system tmp dir.
+    base::FilePath tmp_dir;
+    ASSERT_TRUE(GetTempDir(&tmp_dir));
+
+    // Creates a test dir for ListFiles testing.
+    base::FilePath test_dir;
+    ASSERT_TRUE(base::CreateTemporaryDirInDir(tmp_dir, "list-file-tests.", &test_dir));
+
+    // Generates dummy files to list.
+    base::FilePath file_path_1 = test_dir.Append("1.txt");
+    ASSERT_TRUE(base::WriteFile(file_path_1, "1", 1));
+    base::FilePath file_path_2 = test_dir.Append("2.txt");
+    ASSERT_TRUE(base::WriteFile(file_path_2, "22", 2));
+    base::FilePath file_path_3 = test_dir.Append("3.txt");
+    ASSERT_TRUE(base::WriteFile(file_path_3, "333", 3));
+
+    // List files for comparison.
+    auto result = ListFiles(test_dir.value());
+    ASSERT_TRUE(result);
+    ASSERT_TRUE(result.has_value());
+    auto files = result.value();
+    EXPECT_EQ(3UL, files.size());
+    // Sort them offline for comparison.
+    std::sort(files.begin(), files.end());
+    EXPECT_EQ(file_path_1.value(), files[0]);
+    EXPECT_EQ(file_path_2.value(), files[1]);
+    EXPECT_EQ(file_path_3.value(), files[2]);
+
+    ASSERT_TRUE(base::DeleteFile(test_dir, true /* resursive */));
+}
+
+TEST(BasicUtilTest, ListFilesShouldDiscardSymlink) {
+    // Gets system tmp dir.
+    base::FilePath tmp_dir;
+    ASSERT_TRUE(GetTempDir(&tmp_dir));
+
+    // Creates a test dir for ListFiles testing.
+    base::FilePath test_dir;
+    ASSERT_TRUE(base::CreateTemporaryDirInDir(tmp_dir, "list-file-tests.", &test_dir));
+
+    // Generates dummy files to list.
+    base::FilePath file_path_1 = test_dir.Append("1.txt");
+    ASSERT_TRUE(base::WriteFile(file_path_1, "1", 1));
+    base::FilePath file_path_2 = test_dir.Append("2.txt");
+    ASSERT_TRUE(base::WriteFile(file_path_2, "22", 2));
+    // Creates a symlink and checks it won't be returned by ListFiles.
+    base::FilePath file_path_3 = test_dir.Append("3.txt");
+    base::FilePath non_existent_target = test_dir.Append("non_existent_target.txt");
+    ASSERT_TRUE(base::CreateSymbolicLink(non_existent_target, file_path_3));
+
+    // List files for comparison.
+    auto result = ListFiles(test_dir.value());
+    ASSERT_TRUE(result);
+    ASSERT_TRUE(result.has_value());
+    auto files = result.value();
+    EXPECT_EQ(2UL, files.size());  // Should not include the symlink file.
+    // Sort them offline for comparison.
+    std::sort(files.begin(), files.end());
+    EXPECT_EQ(file_path_1.value(), files[0]);
+    EXPECT_EQ(file_path_2.value(), files[1]);
+
+    ASSERT_TRUE(base::DeleteFile(test_dir, true /* resursive */));
+}
+
+TEST(BasicUtilTest, ListFilesOpenDirFailure) {
+    // Gets system tmp dir.
+    base::FilePath tmp_dir;
+    ASSERT_TRUE(GetTempDir(&tmp_dir));
+
+    // Generates dummy files to list.
+    base::FilePath no_such_dir = tmp_dir.Append("not_such_dir");
+
+    auto fail = ListFiles(no_such_dir.value());
+    ASSERT_FALSE(fail);
+    EXPECT_EQ(ENOENT, fail.error().code());
+    EXPECT_TRUE(android::base::StartsWith(fail.error().message(), "Failed to opendir: "));
+}
+
+TEST(BasicUtilTest, ListFilesEmptyDir) {
+    // Gets system tmp dir.
+    base::FilePath tmp_dir;
+    ASSERT_TRUE(GetTempDir(&tmp_dir));
+
+    // Creates a test dir for ListFiles testing.
+    base::FilePath test_dir;
+    ASSERT_TRUE(base::CreateTemporaryDirInDir(tmp_dir, "list-file-tests.", &test_dir));
+
+    // List files without sorting.
+    auto result = ListFiles(test_dir.value());
+    ASSERT_TRUE(result);
+    ASSERT_TRUE(result.has_value());
+    auto files = result.value();
+    EXPECT_EQ(0UL, files.size());
+
+    ASSERT_TRUE(base::DeleteFile(test_dir, true /* resursive */));
+}
+
 }  // namespace fs_avb_host_test
diff --git a/fs_mgr/libfs_avb/util.cpp b/fs_mgr/libfs_avb/util.cpp
index d214b5b..7783d04 100644
--- a/fs_mgr/libfs_avb/util.cpp
+++ b/fs_mgr/libfs_avb/util.cpp
@@ -16,10 +16,13 @@
 
 #include "util.h"
 
+#include <dirent.h>
 #include <sys/ioctl.h>
+#include <sys/types.h>
 
 #include <thread>
 
+#include <android-base/stringprintf.h>
 #include <android-base/unique_fd.h>
 #include <linux/fs.h>
 
@@ -122,5 +125,23 @@
     return ioctl(fd, BLKROSET, &ON) == 0;
 }
 
+Result<std::vector<std::string>> ListFiles(const std::string& dir) {
+    struct dirent* de;
+    std::vector<std::string> files;
+
+    std::unique_ptr<DIR, int (*)(DIR*)> dirp(opendir(dir.c_str()), closedir);
+    if (!dirp) {
+        return ErrnoError() << "Failed to opendir: " << dir;
+    }
+
+    while ((de = readdir(dirp.get()))) {
+        if (de->d_type != DT_REG) continue;
+        std::string full_path = android::base::StringPrintf("%s/%s", dir.c_str(), de->d_name);
+        files.emplace_back(std::move(full_path));
+    }
+
+    return files;
+}
+
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/fs_mgr/libfs_avb/util.h b/fs_mgr/libfs_avb/util.h
index 7763da5..427ab7c 100644
--- a/fs_mgr/libfs_avb/util.h
+++ b/fs_mgr/libfs_avb/util.h
@@ -18,6 +18,7 @@
 
 #include <chrono>
 #include <string>
+#include <vector>
 
 #ifdef HOST_TEST
 #include <base/logging.h>
@@ -25,6 +26,11 @@
 #include <android-base/logging.h>
 #endif
 
+#include <android-base/result.h>
+
+using android::base::ErrnoError;
+using android::base::Result;
+
 #define FS_AVB_TAG "[libfs_avb]"
 
 // Logs a message to kernel
@@ -60,5 +66,8 @@
 
 bool SetBlockDeviceReadOnly(const std::string& blockdev);
 
+// Returns a list of file under the dir, no order is guaranteed.
+Result<std::vector<std::string>> ListFiles(const std::string& dir);
+
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/init/Android.mk b/init/Android.mk
index ade4fb5..ee2d89a 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -75,7 +75,6 @@
 
 # Set up the directories that first stage init mounts on.
 LOCAL_POST_INSTALL_CMD := mkdir -p \
-    $(TARGET_RAMDISK_OUT)/apex \
     $(TARGET_RAMDISK_OUT)/debug_ramdisk \
     $(TARGET_RAMDISK_OUT)/dev \
     $(TARGET_RAMDISK_OUT)/mnt \
diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp
index ac44796..bd71cb5 100644
--- a/init/first_stage_init.cpp
+++ b/init/first_stage_init.cpp
@@ -204,10 +204,6 @@
     // part of the product partition, e.g. because they are mounted read-write.
     CHECKCALL(mkdir("/mnt/product", 0755));
 
-    // /apex is used to mount APEXes
-    CHECKCALL(mount("tmpfs", "/apex", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
-                    "mode=0755,uid=0,gid=0"));
-
     // /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"));
diff --git a/init/init.cpp b/init/init.cpp
index 6ba64ee..5f97e44 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -512,10 +512,24 @@
 
 static void UmountDebugRamdisk() {
     if (umount("/debug_ramdisk") != 0) {
-        LOG(ERROR) << "Failed to umount /debug_ramdisk";
+        PLOG(ERROR) << "Failed to umount /debug_ramdisk";
     }
 }
 
+static void MountExtraFilesystems() {
+#define CHECKCALL(x) \
+    if ((x) != 0) PLOG(FATAL) << #x " failed.";
+
+    // /apex is used to mount APEXes
+    CHECKCALL(mount("tmpfs", "/apex", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
+                    "mode=0755,uid=0,gid=0"));
+
+    // /linkerconfig is used to keep generated linker configuration
+    CHECKCALL(mount("tmpfs", "/linkerconfig", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
+                    "mode=0755,uid=0,gid=0"));
+#undef CHECKCALL
+}
+
 static void RecordStageBoottimes(const boot_clock::time_point& second_stage_start_time) {
     int64_t first_stage_start_time_ns = -1;
     if (auto first_stage_start_time_str = getenv(kEnvFirstStageStartedAt);
@@ -656,6 +670,9 @@
         UmountDebugRamdisk();
     }
 
+    // Mount extra filesystems required during second stage init
+    MountExtraFilesystems();
+
     // Now set up SELinux for second stage.
     SelinuxSetupKernelLogging();
     SelabelInitialize();
diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp
index 940fb6b..c33e0de 100644
--- a/init/mount_namespace.cpp
+++ b/init/mount_namespace.cpp
@@ -172,6 +172,11 @@
     // the bootstrap namespace get APEXes from the read-only partition.
     if (!(MakePrivate("/apex"))) return false;
 
+    // /linkerconfig is a private mountpoint to give a different linker configuration
+    // based on the mount namespace. Subdirectory will be bind-mounted based on current mount
+    // namespace
+    if (!(MakePrivate("/linkerconfig"))) return false;
+
     bootstrap_ns_fd.reset(OpenMountNamespace());
     bootstrap_ns_id = GetMountNamespaceId();
 
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 2fc8f6d..852d6ca 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -531,6 +531,8 @@
     selinux_android_restorecon("/dev/device-mapper", 0);
 
     selinux_android_restorecon("/apex", 0);
+
+    selinux_android_restorecon("/linkerconfig", 0);
 }
 
 int SelinuxKlogCallback(int type, const char* fmt, ...) {
diff --git a/init/service.cpp b/init/service.cpp
index be46585..a97935e 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -326,6 +326,7 @@
                                << (boot_completed ? "in 4 minutes" : "before boot completed");
                     // Notifies update_verifier and apexd
                     SetProperty("sys.init.updatable_crashing", "1");
+                    SetProperty("sys.init.updatable_crashing_process_name", name_);
                 }
             }
         } else {
diff --git a/libutils/Errors.cpp b/libutils/Errors.cpp
index 2dfd138..74f3bef 100644
--- a/libutils/Errors.cpp
+++ b/libutils/Errors.cpp
@@ -45,7 +45,7 @@
 #undef STATUS_CASE
     }
 
-    return std::to_string(s) + ' ' + strerror(-s);
+    return std::to_string(s) + " (" + strerror(-s) + ")";
 }
 
 }  // namespace android
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 002c690..ebc0cde 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -72,7 +72,8 @@
 #
 # create some directories (some are mount points) and symlinks
 LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
-    dev proc sys system data odm oem acct config storage mnt apex debug_ramdisk $(BOARD_ROOT_EXTRA_FOLDERS)); \
+    dev proc sys system data odm oem acct config storage mnt apex debug_ramdisk \
+    linkerconfig $(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; \
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 88b6da4..2ec0669 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -38,12 +38,9 @@
     # Allow up to 32K FDs per process
     setrlimit nofile 32768 32768
 
-    # Create directory to keep ld.config.txt
-    mkdir /dev/linkerconfig 0755
-
     # Generate ld.config.txt for early executed processes
-    exec -- /system/bin/linkerconfig --target /dev/linkerconfig/ld.config.txt
-    chmod 444 /dev/linkerconfig/ld.config.txt
+    exec -- /system/bin/linkerconfig --target /linkerconfig/ld.config.txt
+    chmod 444 /linkerconfig/ld.config.txt
 
     start ueventd