Merge "Reland: "init: chroot from recovery to /first_stage_ramdisk""
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index 1e031ad..6b4901b 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -113,18 +113,7 @@
     if (!metadata) {
         return nullptr;
     }
-    std::unique_ptr<MetadataBuilder> builder = New(*metadata.get());
-    if (!builder) {
-        return nullptr;
-    }
-    for (size_t i = 0; i < builder->block_devices_.size(); i++) {
-        std::string partition_name = GetBlockDevicePartitionName(builder->block_devices_[i]);
-        BlockDeviceInfo device_info;
-        if (opener.GetInfo(partition_name, &device_info)) {
-            builder->UpdateBlockDeviceInfo(i, device_info);
-        }
-    }
-    return builder;
+    return New(*metadata.get(), &opener);
 }
 
 std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const std::string& super_partition,
@@ -142,14 +131,69 @@
     return builder;
 }
 
-std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const LpMetadata& metadata) {
+std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const LpMetadata& metadata,
+                                                      const IPartitionOpener* opener) {
     std::unique_ptr<MetadataBuilder> builder(new MetadataBuilder());
     if (!builder->Init(metadata)) {
         return nullptr;
     }
+    if (opener) {
+        for (size_t i = 0; i < builder->block_devices_.size(); i++) {
+            std::string partition_name = GetBlockDevicePartitionName(builder->block_devices_[i]);
+            BlockDeviceInfo device_info;
+            if (opener->GetInfo(partition_name, &device_info)) {
+                builder->UpdateBlockDeviceInfo(i, device_info);
+            }
+        }
+    }
     return builder;
 }
 
+std::unique_ptr<MetadataBuilder> MetadataBuilder::NewForUpdate(const IPartitionOpener& opener,
+                                                               const std::string& source_partition,
+                                                               uint32_t source_slot_number,
+                                                               uint32_t target_slot_number) {
+    auto metadata = ReadMetadata(opener, source_partition, source_slot_number);
+    if (!metadata) {
+        return nullptr;
+    }
+
+    // Get the list of devices we already have.
+    std::set<std::string> block_devices;
+    for (const auto& block_device : metadata->block_devices) {
+        block_devices.emplace(GetBlockDevicePartitionName(block_device));
+    }
+
+    auto new_block_devices = metadata->block_devices;
+
+    // Add missing block devices.
+    std::string source_slot_suffix = SlotSuffixForSlotNumber(source_slot_number);
+    std::string target_slot_suffix = SlotSuffixForSlotNumber(target_slot_number);
+    for (const auto& block_device : metadata->block_devices) {
+        std::string partition_name = GetBlockDevicePartitionName(block_device);
+        std::string slot_suffix = GetPartitionSlotSuffix(partition_name);
+        if (slot_suffix.empty() || slot_suffix != source_slot_suffix) {
+            continue;
+        }
+        std::string new_name =
+                partition_name.substr(0, partition_name.size() - slot_suffix.size()) +
+                target_slot_suffix;
+        if (block_devices.find(new_name) != block_devices.end()) {
+            continue;
+        }
+
+        auto new_device = block_device;
+        if (!UpdateBlockDevicePartitionName(&new_device, new_name)) {
+            LERROR << "Partition name too long: " << new_name;
+            return nullptr;
+        }
+        new_block_devices.emplace_back(new_device);
+    }
+
+    metadata->block_devices = new_block_devices;
+    return New(*metadata.get(), &opener);
+}
+
 MetadataBuilder::MetadataBuilder() : auto_slot_suffixing_(false) {
     memset(&geometry_, 0, sizeof(geometry_));
     geometry_.magic = LP_METADATA_GEOMETRY_MAGIC;
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
index 47ebf6d..59717d1 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -150,10 +150,24 @@
     static std::unique_ptr<MetadataBuilder> New(const std::string& super_partition,
                                                 uint32_t slot_number);
 
+    // This is when performing an A/B update. The source partition must be a
+    // super partition. On a normal device, the metadata for the source slot
+    // is imported and the target slot is ignored. On a retrofit device, the
+    // metadata may not have the target slot's devices listed yet, in which
+    // case, it is automatically upgraded to include all available block
+    // devices.
+    static std::unique_ptr<MetadataBuilder> NewForUpdate(const IPartitionOpener& opener,
+                                                         const std::string& source_partition,
+                                                         uint32_t source_slot_number,
+                                                         uint32_t target_slot_number);
+
     // Import an existing table for modification. If the table is not valid, for
     // example it contains duplicate partition names, then nullptr is returned.
-    // This method is for testing or changing off-line tables.
-    static std::unique_ptr<MetadataBuilder> New(const LpMetadata& metadata);
+    //
+    // If an IPartitionOpener is specified, then block device informatiom will
+    // be updated.
+    static std::unique_ptr<MetadataBuilder> New(const LpMetadata& metadata,
+                                                const IPartitionOpener* opener = nullptr);
 
     // Helper function for a single super partition, for tests.
     static std::unique_ptr<MetadataBuilder> New(const BlockDeviceInfo& device_info,
diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp
index 5f0d9c8..9acf23e 100644
--- a/fs_mgr/liblp/io_test.cpp
+++ b/fs_mgr/liblp/io_test.cpp
@@ -649,3 +649,42 @@
     ASSERT_EQ(metadata->block_devices.size(), static_cast<size_t>(1));
     EXPECT_EQ(GetBlockDevicePartitionName(metadata->block_devices[0]), "super_a");
 }
+
+TEST(liblp, UpdateRetrofit) {
+    unique_ptr<MetadataBuilder> builder = CreateDefaultBuilder();
+    ASSERT_NE(builder, nullptr);
+    ASSERT_TRUE(AddDefaultPartitions(builder.get()));
+    builder->SetAutoSlotSuffixing();
+
+    auto fd = CreateFakeDisk();
+    ASSERT_GE(fd, 0);
+
+    // Note: we bind the same fd to both names, since we want to make sure the
+    // exact same bits are getting read back in each test.
+    TestPartitionOpener opener({{"super_a", fd}, {"super_b", fd}},
+                               {{"super_a", kSuperInfo}, {"super_b", kSuperInfo}});
+    auto exported = builder->Export();
+    ASSERT_NE(exported, nullptr);
+    ASSERT_TRUE(FlashPartitionTable(opener, "super_a", *exported.get()));
+
+    builder = MetadataBuilder::NewForUpdate(opener, "super_a", 0, 1);
+    ASSERT_NE(builder, nullptr);
+    auto updated = builder->Export();
+    ASSERT_NE(updated, nullptr);
+    ASSERT_EQ(updated->block_devices.size(), static_cast<size_t>(2));
+    EXPECT_EQ(GetBlockDevicePartitionName(updated->block_devices[0]), "super_a");
+    EXPECT_EQ(GetBlockDevicePartitionName(updated->block_devices[1]), "super_b");
+}
+
+TEST(liblp, UpdateNonRetrofit) {
+    unique_fd fd = CreateFlashedDisk();
+    ASSERT_GE(fd, 0);
+
+    DefaultPartitionOpener opener(fd);
+    auto builder = MetadataBuilder::NewForUpdate(opener, "super", 0, 1);
+    ASSERT_NE(builder, nullptr);
+    auto updated = builder->Export();
+    ASSERT_NE(updated, nullptr);
+    ASSERT_EQ(updated->block_devices.size(), static_cast<size_t>(1));
+    EXPECT_EQ(GetBlockDevicePartitionName(updated->block_devices[0]), "super");
+}
diff --git a/fs_mgr/liblp/reader.cpp b/fs_mgr/liblp/reader.cpp
index 3319956..b36ba0e 100644
--- a/fs_mgr/liblp/reader.cpp
+++ b/fs_mgr/liblp/reader.cpp
@@ -369,12 +369,10 @@
             continue;
         }
         std::string partition_name = GetBlockDevicePartitionName(block_device) + slot_suffix;
-        if (partition_name.size() > sizeof(block_device.partition_name)) {
+        if (!UpdateBlockDevicePartitionName(&block_device, partition_name)) {
             LERROR << __PRETTY_FUNCTION__ << " partition name too long: " << partition_name;
             return false;
         }
-        strncpy(block_device.partition_name, partition_name.c_str(),
-                sizeof(block_device.partition_name));
         block_device.flags &= ~LP_BLOCK_DEVICE_SLOT_SUFFIXED;
     }
     return true;
diff --git a/fs_mgr/liblp/utility.cpp b/fs_mgr/liblp/utility.cpp
index 2d34ce5..4f20b6b 100644
--- a/fs_mgr/liblp/utility.cpp
+++ b/fs_mgr/liblp/utility.cpp
@@ -137,5 +137,13 @@
     return (slot_number == 0) ? "_a" : "_b";
 }
 
+bool UpdateBlockDevicePartitionName(LpMetadataBlockDevice* device, const std::string& name) {
+    if (name.size() > sizeof(device->partition_name)) {
+        return false;
+    }
+    strncpy(device->partition_name, name.c_str(), sizeof(device->partition_name));
+    return true;
+}
+
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/fs_mgr/liblp/utility.h b/fs_mgr/liblp/utility.h
index 65e643b..55ecb5a 100644
--- a/fs_mgr/liblp/utility.h
+++ b/fs_mgr/liblp/utility.h
@@ -84,6 +84,9 @@
     return aligned;
 }
 
+// Update names from C++ strings.
+bool UpdateBlockDevicePartitionName(LpMetadataBlockDevice* device, const std::string& name);
+
 }  // namespace fs_mgr
 }  // namespace android
 
diff --git a/init/README.md b/init/README.md
index 2c531df..4b21e32 100644
--- a/init/README.md
+++ b/init/README.md
@@ -275,6 +275,10 @@
   since it has some peculiarities for backwards compatibility reasons. The 'imports' section of
   this file has more details on the order.
 
+`parse_apex_configs`
+  Parses config file(s) from the mounted APEXes. Intented to be used only once
+  when apexd notifies the mount event by setting apexd.status to ready.
+
 `priority <priority>`
 > Scheduling priority of the service process. This value has to be in range
   -20 to 19. Default priority is 0. Priority is set via setpriority().
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 5d62c0b..8660d2a 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -20,6 +20,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <fts.h>
+#include <glob.h>
 #include <linux/loop.h>
 #include <linux/module.h>
 #include <mntent.h>
@@ -1053,6 +1054,38 @@
         {{"exec", "/system/bin/vdc", "--wait", "cryptfs", "init_user0"}, args.context});
 }
 
+static Result<Success> do_parse_apex_configs(const BuiltinArguments& args) {
+    glob_t glob_result;
+    // @ is added to filter out the later paths, which are bind mounts of the places
+    // where the APEXes are really mounted at. Otherwise, we will parse the
+    // same file twice.
+    static constexpr char glob_pattern[] = "/apex/*@*/etc/*.rc";
+    if (glob(glob_pattern, GLOB_MARK, nullptr, &glob_result) != 0) {
+        globfree(&glob_result);
+        return Error() << "glob pattern '" << glob_pattern << "' failed";
+    }
+    std::vector<std::string> configs;
+    Parser parser = CreateServiceOnlyParser(ServiceList::GetInstance());
+    for (size_t i = 0; i < glob_result.gl_pathc; i++) {
+        configs.emplace_back(glob_result.gl_pathv[i]);
+    }
+    globfree(&glob_result);
+
+    bool success = true;
+    for (const auto& c : configs) {
+        if (c.back() == '/') {
+            // skip if directory
+            continue;
+        }
+        success &= parser.ParseConfigFile(c);
+    }
+    if (success) {
+        return Success();
+    } else {
+        return Error() << "Could not parse apex configs";
+    }
+}
+
 // Builtin-function-map start
 const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
     constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
@@ -1090,6 +1123,7 @@
         // mount and umount are run in the same context as mount_all for symmetry.
         {"mount_all",               {1,     kMax, {false,  do_mount_all}}},
         {"mount",                   {3,     kMax, {false,  do_mount}}},
+        {"parse_apex_configs",      {0,     0,    {false,  do_parse_apex_configs}}},
         {"umount",                  {1,     1,    {false,  do_umount}}},
         {"readahead",               {1,     2,    {true,   do_readahead}}},
         {"restart",                 {1,     1,    {false,  do_restart}}},
diff --git a/init/init.cpp b/init/init.cpp
index 90803f7..e7dbc11 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -132,6 +132,14 @@
     return parser;
 }
 
+// parser that only accepts new services
+Parser CreateServiceOnlyParser(ServiceList& service_list) {
+    Parser parser;
+
+    parser.AddSectionParser("service", std::make_unique<ServiceParser>(&service_list, subcontexts));
+    return parser;
+}
+
 static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
     Parser parser = CreateParser(action_manager, service_list);
 
diff --git a/init/init.h b/init/init.h
index f244ad7..65405aa 100644
--- a/init/init.h
+++ b/init/init.h
@@ -38,6 +38,7 @@
 extern std::vector<std::string> late_import_paths;
 
 Parser CreateParser(ActionManager& action_manager, ServiceList& service_list);
+Parser CreateServiceOnlyParser(ServiceList& service_list);
 
 void HandleControlMessage(const std::string& msg, const std::string& arg, pid_t pid);
 
diff --git a/init/parser.h b/init/parser.h
index 2454b6a..f30bda7 100644
--- a/init/parser.h
+++ b/init/parser.h
@@ -72,6 +72,7 @@
     Parser();
 
     bool ParseConfig(const std::string& path);
+    bool ParseConfigFile(const std::string& path);
     void AddSectionParser(const std::string& name, std::unique_ptr<SectionParser> parser);
     void AddSingleLineParser(const std::string& prefix, LineCallback callback);
 
@@ -82,7 +83,6 @@
 
   private:
     void ParseData(const std::string& filename, std::string* data);
-    bool ParseConfigFile(const std::string& path);
     bool ParseConfigDir(const std::string& path);
 
     std::map<std::string, std::unique_ptr<SectionParser>> section_parsers_;
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index bd5f26f..ee52f5e 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -60,7 +60,7 @@
 // way up to the root.
 
 static const struct fs_path_config android_dirs[] = {
-    // clang-format off
+        // clang-format off
     { 00770, AID_SYSTEM,       AID_CACHE,        0, "cache" },
     { 00555, AID_ROOT,         AID_ROOT,         0, "config" },
     { 00771, AID_SYSTEM,       AID_SYSTEM,       0, "data/app" },
@@ -80,17 +80,18 @@
     { 00775, AID_ROOT,         AID_ROOT,         0, "data/preloads" },
     { 00771, AID_SYSTEM,       AID_SYSTEM,       0, "data" },
     { 00755, AID_ROOT,         AID_SYSTEM,       0, "mnt" },
-    { 00755, AID_ROOT,         AID_SHELL,        0, "product/bin" },
+    { 00751, AID_ROOT,         AID_SHELL,        0, "product/bin" },
     { 00750, AID_ROOT,         AID_SHELL,        0, "sbin" },
     { 00777, AID_ROOT,         AID_ROOT,         0, "sdcard" },
     { 00751, AID_ROOT,         AID_SDCARD_R,     0, "storage" },
-    { 00755, AID_ROOT,         AID_SHELL,        0, "system/bin" },
+    { 00751, AID_ROOT,         AID_SHELL,        0, "system/bin" },
     { 00755, AID_ROOT,         AID_ROOT,         0, "system/etc/ppp" },
     { 00755, AID_ROOT,         AID_SHELL,        0, "system/vendor" },
-    { 00755, AID_ROOT,         AID_SHELL,        0, "system/xbin" },
+    { 00751, AID_ROOT,         AID_SHELL,        0, "system/xbin" },
+    { 00751, AID_ROOT,         AID_SHELL,        0, "vendor/bin" },
     { 00755, AID_ROOT,         AID_SHELL,        0, "vendor" },
     { 00755, AID_ROOT,         AID_ROOT,         0, 0 },
-    // clang-format on
+        // clang-format on
 };
 #ifndef __ANDROID_VNDK__
 auto __for_testing_only__android_dirs = android_dirs;
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 025e3c3..636daea 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -801,3 +801,6 @@
 service flash_recovery /system/bin/install-recovery.sh
     class main
     oneshot
+
+on property:apexd.status=ready
+    parse_apex_configs