Merge "Revert "Add support for /system_dlkm partition for GKI modules.""
diff --git a/apex/com.android.hardware.core_permissions/Android.bp b/apex/com.google.aosp_cf_phone.hardware.core_permissions/Android.bp
similarity index 96%
rename from apex/com.android.hardware.core_permissions/Android.bp
rename to apex/com.google.aosp_cf_phone.hardware.core_permissions/Android.bp
index 11e28d7..85631d1 100644
--- a/apex/com.android.hardware.core_permissions/Android.bp
+++ b/apex/com.google.aosp_cf_phone.hardware.core_permissions/Android.bp
@@ -17,7 +17,7 @@
 }
 
 override_apex {
-    name: "com.google.aosp_cf_x86_64_phone.hardware.core_permissions",
+    name: "com.google.aosp_cf_phone.hardware.core_permissions",
     base: "com.android.hardware.core_permissions",
     prebuilts: [
         "android.hardware.audio.low_latency.prebuilt.xml",
diff --git a/apex/com.google.aosp_cf_x86_64_phone.rros/Android.bp b/apex/com.google.aosp_cf_phone.rros/Android.bp
similarity index 95%
rename from apex/com.google.aosp_cf_x86_64_phone.rros/Android.bp
rename to apex/com.google.aosp_cf_phone.rros/Android.bp
index e988ecf..34ca2c3 100644
--- a/apex/com.google.aosp_cf_x86_64_phone.rros/Android.bp
+++ b/apex/com.google.aosp_cf_phone.rros/Android.bp
@@ -17,7 +17,7 @@
 }
 
 apex {
-    name: "com.google.aosp_cf_x86_64_phone.rros",
+    name: "com.google.aosp_cf_phone.rros",
     manifest: "apex_manifest.json",
     key: "com.google.cf.apex.key",
     certificate: ":com.google.cf.apex.certificate",
diff --git a/apex/com.google.aosp_cf_phone.rros/apex_manifest.json b/apex/com.google.aosp_cf_phone.rros/apex_manifest.json
new file mode 100644
index 0000000..e5ebe27
--- /dev/null
+++ b/apex/com.google.aosp_cf_phone.rros/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+  "name": "com.google.aosp_cf_phone.rros",
+  "version": 1
+}
diff --git a/apex/com.google.aosp_cf_x86_64_phone.rros/file_contexts b/apex/com.google.aosp_cf_phone.rros/file_contexts
similarity index 100%
rename from apex/com.google.aosp_cf_x86_64_phone.rros/file_contexts
rename to apex/com.google.aosp_cf_phone.rros/file_contexts
diff --git a/apex/com.google.aosp_cf_x86_64_phone.rros/apex_manifest.json b/apex/com.google.aosp_cf_x86_64_phone.rros/apex_manifest.json
deleted file mode 100644
index 47cefb5..0000000
--- a/apex/com.google.aosp_cf_x86_64_phone.rros/apex_manifest.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-  "name": "com.google.aosp_cf_x86_64_phone.rros",
-  "version": 1
-}
diff --git a/guest/hals/keymint/remote/remote_remotely_provisioned_component.cpp b/guest/hals/keymint/remote/remote_remotely_provisioned_component.cpp
index 7d2eca1..059a3d7 100644
--- a/guest/hals/keymint/remote/remote_remotely_provisioned_component.cpp
+++ b/guest/hals/keymint/remote/remote_remotely_provisioned_component.cpp
@@ -57,6 +57,7 @@
   info->versionNumber = 1;
   info->rpcAuthorName = "Google";
   info->supportedEekCurve = RpcHardwareInfo::CURVE_25519;
+  info->uniqueId = "remote keymint";
   return ScopedAStatus::ok();
 }
 
diff --git a/host/commands/assemble_cvd/assemble_cvd.cc b/host/commands/assemble_cvd/assemble_cvd.cc
index 77d0337..5dccc1d 100644
--- a/host/commands/assemble_cvd/assemble_cvd.cc
+++ b/host/commands/assemble_cvd/assemble_cvd.cc
@@ -180,6 +180,7 @@
       preserving.insert("boot_repacked.img");
       preserving.insert("vendor_boot_repacked.img");
       preserving.insert("access-kregistry");
+      preserving.insert("hwcomposer-pmem");
       preserving.insert("NVChip");
       preserving.insert("gatekeeper_secure");
       preserving.insert("gatekeeper_insecure");
diff --git a/host/commands/assemble_cvd/disk_flags.cc b/host/commands/assemble_cvd/disk_flags.cc
index e01929e..95ca27c 100644
--- a/host/commands/assemble_cvd/disk_flags.cc
+++ b/host/commands/assemble_cvd/disk_flags.cc
@@ -248,6 +248,7 @@
 }
 
 std::vector<ImagePartition> persistent_composite_disk_config(
+    const CuttlefishConfig& config,
     const CuttlefishConfig::InstanceSpecific& instance) {
   std::vector<ImagePartition> partitions;
 
@@ -264,14 +265,16 @@
         .image_file_path = instance.factory_reset_protected_path(),
     });
   }
-  partitions.push_back(ImagePartition{
-      .label = "bootconfig",
-      .image_file_path = instance.persistent_bootconfig_path(),
-  });
-  partitions.push_back(ImagePartition{
-      .label = "vbmeta",
-      .image_file_path = instance.vbmeta_path(),
-  });
+  if (config.bootconfig_supported()) {
+    partitions.push_back(ImagePartition{
+        .label = "bootconfig",
+        .image_file_path = instance.persistent_bootconfig_path(),
+    });
+    partitions.push_back(ImagePartition{
+        .label = "vbmeta",
+        .image_file_path = instance.vbmeta_path(),
+    });
+  }
   return partitions;
 }
 
@@ -406,10 +409,11 @@
         instance.PerInstancePath("persistent_composite_gpt_header.img");
     std::string footer_path =
         instance.PerInstancePath("persistent_composite_gpt_footer.img");
-    CreateCompositeDisk(persistent_composite_disk_config(instance), header_path,
-                        footer_path, instance.persistent_composite_disk_path());
+    CreateCompositeDisk(persistent_composite_disk_config(config, instance),
+                        header_path, footer_path,
+                        instance.persistent_composite_disk_path());
   } else {
-    AggregateImage(persistent_composite_disk_config(instance),
+    AggregateImage(persistent_composite_disk_config(config, instance),
                    instance.persistent_composite_disk_path());
   }
   return true;
@@ -508,7 +512,14 @@
   std::string Name() const override {
     return "GeneratePersistentBootconfigAndVbmeta";
   }
-  bool Enabled() const override { return !config_.protected_vm(); }
+  //  Cuttlefish for the time being won't be able to support OTA from a
+  //  non-bootconfig kernel to a bootconfig-kernel (or vice versa) IF the
+  //  device is stopped (via stop_cvd). This is rarely an issue since OTA
+  //  testing run on cuttlefish is done within one launch cycle of the device.
+  //  If this ever becomes an issue, this code will have to be rewritten.
+  bool Enabled() const override {
+    return (!config_.protected_vm() && config_.bootconfig_supported());
+  }
 
  private:
   std::unordered_set<Feature*> Dependencies() const override { return {}; }
@@ -528,15 +539,6 @@
       return false;
     }
 
-    //  Cuttlefish for the time being won't be able to support OTA from a
-    //  non-bootconfig kernel to a bootconfig-kernel (or vice versa) IF the
-    //  device is stopped (via stop_cvd). This is rarely an issue since OTA
-    //  testing run on cuttlefish is done within one launch cycle of the device.
-    //  If this ever becomes an issue, this code will have to be rewritten.
-    if (!config_.bootconfig_supported()) {
-      return true;
-    }
-
     const std::string bootconfig =
         android::base::Join(BootconfigArgsFromConfig(config_, instance_),
                             "\n") +
@@ -679,6 +681,37 @@
   const CuttlefishConfig::InstanceSpecific& instance_;
 };
 
+class InitializeHwcomposerPmemImage : public Feature {
+ public:
+  INJECT(InitializeHwcomposerPmemImage(
+      const CuttlefishConfig& config,
+      const CuttlefishConfig::InstanceSpecific& instance))
+      : config_(config), instance_(instance) {}
+
+  // Feature
+  std::string Name() const override { return "InitializeHwcomposerPmemImage"; }
+  bool Enabled() const override { return !config_.protected_vm(); }
+
+ private:
+  std::unordered_set<Feature*> Dependencies() const override { return {}; }
+  bool Setup() {
+    if (FileExists(instance_.hwcomposer_pmem_path())) {
+      return true;
+    }
+    bool success =
+        CreateBlankImage(instance_.hwcomposer_pmem_path(), 2 /* mb */, "none");
+    if (!success) {
+      LOG(ERROR) << "Failed to create hwcomposer pmem image \""
+                 << instance_.hwcomposer_pmem_path() << "\"";
+      return false;
+    }
+    return true;
+  }
+
+  const CuttlefishConfig& config_;
+  const CuttlefishConfig::InstanceSpecific& instance_;
+};
+
 class InitializePstore : public Feature {
  public:
   INJECT(InitializePstore(const CuttlefishConfig& config,
@@ -772,6 +805,105 @@
   const CuttlefishConfig::InstanceSpecific& instance_;
 };
 
+class InitializeInstanceCompositeDisk : public Feature {
+ public:
+  INJECT(InitializeInstanceCompositeDisk(
+      const CuttlefishConfig& config,
+      const CuttlefishConfig::InstanceSpecific& instance,
+      InitializeFactoryResetProtected& frp,
+      InitBootloaderEnvPartition& bootloader_env,
+      GeneratePersistentBootconfigAndVbmeta& bootconfig))
+      : config_(config),
+        instance_(instance),
+        frp_(frp),
+        bootloader_env_(bootloader_env),
+        bootconfig_(bootconfig) {}
+
+  std::string Name() const override {
+    return "InitializeInstanceCompositeDisk";
+  }
+  bool Enabled() const override { return true; }
+
+ private:
+  std::unordered_set<Feature*> Dependencies() const override {
+    return {
+        static_cast<Feature*>(&frp_),
+        static_cast<Feature*>(&bootloader_env_),
+        static_cast<Feature*>(&bootconfig_),
+    };
+  }
+  bool Setup() override {
+    bool compositeMatchesDiskConfig = DoesCompositeMatchCurrentDiskConfig(
+        instance_.PerInstancePath("persistent_composite_disk_config.txt"),
+        persistent_composite_disk_config(config_, instance_));
+    bool oldCompositeDisk =
+        ShouldCreateCompositeDisk(instance_.persistent_composite_disk_path(),
+                                  persistent_composite_disk_config(config_, instance_));
+
+    if (!compositeMatchesDiskConfig || oldCompositeDisk) {
+      bool success = CreatePersistentCompositeDisk(config_, instance_);
+      if (!success) {
+        LOG(ERROR) << "Failed to create persistent composite disk";
+        return false;
+      }
+    }
+    return true;
+  }
+
+  const CuttlefishConfig& config_;
+  const CuttlefishConfig::InstanceSpecific& instance_;
+  InitializeFactoryResetProtected& frp_;
+  InitBootloaderEnvPartition& bootloader_env_;
+  GeneratePersistentBootconfigAndVbmeta& bootconfig_;
+};
+
+class VbmetaEnforceMinimumSize : public Feature {
+ public:
+  INJECT(VbmetaEnforceMinimumSize()) {}
+
+  std::string Name() const override { return "VbmetaEnforceMinimumSize"; }
+  bool Enabled() const override { return true; }
+
+ private:
+  std::unordered_set<Feature*> Dependencies() const override { return {}; }
+  bool Setup() override {
+    // libavb expects to be able to read the maximum vbmeta size, so we must
+    // provide a partition which matches this or the read will fail
+    for (const auto& vbmeta_image :
+         {FLAGS_vbmeta_image, FLAGS_vbmeta_system_image}) {
+      if (FileSize(vbmeta_image) != VBMETA_MAX_SIZE) {
+        auto fd = SharedFD::Open(vbmeta_image, O_RDWR);
+        bool success = fd->Truncate(VBMETA_MAX_SIZE) == 0;
+        if (!success) {
+          LOG(ERROR) << "`truncate --size=" << VBMETA_MAX_SIZE << " "
+                     << vbmeta_image << "` "
+                     << "failed: " << fd->StrError();
+          return false;
+        }
+      }
+    }
+    return true;
+  }
+};
+
+class BootloaderPresentCheck : public Feature {
+ public:
+  INJECT(BootloaderPresentCheck()) {}
+
+  std::string Name() const override { return "BootloaderPresentCheck"; }
+  bool Enabled() const override { return true; }
+
+ private:
+  std::unordered_set<Feature*> Dependencies() const override { return {}; }
+  bool Setup() override {
+    if (!FileHasContent(FLAGS_bootloader)) {
+      LOG(ERROR) << "File not found: " << FLAGS_bootloader;
+      return false;
+    }
+    return true;
+  }
+};
+
 static fruit::Component<> DiskChangesComponent(const FetcherConfig* fetcher,
                                                const CuttlefishConfig* config) {
   return fruit::createComponent()
@@ -779,6 +911,8 @@
       .bindInstance(*config)
       .addMultibinding<Feature, InitializeMetadataImage>()
       .addMultibinding<Feature, BootImageRepacker>()
+      .addMultibinding<Feature, VbmetaEnforceMinimumSize>()
+      .addMultibinding<Feature, BootloaderPresentCheck>()
       .install(FixedMiscImagePathComponent, &FLAGS_misc_image)
       .install(InitializeMiscImageComponent)
       .install(FixedDataImagePathComponent, &FLAGS_data_image)
@@ -797,10 +931,12 @@
       .bindInstance(*config)
       .bindInstance(*instance)
       .addMultibinding<Feature, InitializeAccessKregistryImage>()
+      .addMultibinding<Feature, InitializeHwcomposerPmemImage>()
       .addMultibinding<Feature, InitializePstore>()
       .addMultibinding<Feature, InitializeSdCard>()
       .addMultibinding<Feature, InitializeFactoryResetProtected>()
       .addMultibinding<Feature, GeneratePersistentBootconfigAndVbmeta>()
+      .addMultibinding<Feature, InitializeInstanceCompositeDisk>()
       .install(InitBootloaderEnvPartitionComponent);
 }
 
@@ -822,34 +958,6 @@
         << "Failed to run instance feature setup.";
   }
 
-  for (const auto& instance : config.Instances()) {
-    bool compositeMatchesDiskConfig = DoesCompositeMatchCurrentDiskConfig(
-        instance.PerInstancePath("persistent_composite_disk_config.txt"),
-        persistent_composite_disk_config(instance));
-    bool oldCompositeDisk =
-        ShouldCreateCompositeDisk(instance.persistent_composite_disk_path(),
-                                  persistent_composite_disk_config(instance));
-
-    if (!compositeMatchesDiskConfig || oldCompositeDisk) {
-      CHECK(CreatePersistentCompositeDisk(config, instance))
-          << "Failed to create persistent composite disk";
-    }
-  }
-
-  // libavb expects to be able to read the maximum vbmeta size, so we must
-  // provide a partition which matches this or the read will fail
-  for (const auto& vbmeta_image : { FLAGS_vbmeta_image, FLAGS_vbmeta_system_image }) {
-    if (FileSize(vbmeta_image) != VBMETA_MAX_SIZE) {
-      auto fd = SharedFD::Open(vbmeta_image, O_RDWR);
-      CHECK(fd->Truncate(VBMETA_MAX_SIZE) == 0)
-        << "`truncate --size=" << VBMETA_MAX_SIZE << " " << vbmeta_image << "` "
-        << "failed: " << fd->StrError();
-    }
-  }
-
-  CHECK(FileHasContent(FLAGS_bootloader))
-      << "File not found: " << FLAGS_bootloader;
-
   if (SuperImageNeedsRebuilding(fetcher_config, config)) {
     bool success = RebuildSuperImage(fetcher_config, config, FLAGS_super_image);
     CHECK(success) << "Super image rebuilding requested but could not be completed.";
@@ -873,6 +981,9 @@
       if (FileExists(instance.access_kregistry_path())) {
         CreateBlankImage(instance.access_kregistry_path(), 2 /* mb */, "none");
       }
+      if (FileExists(instance.hwcomposer_pmem_path())) {
+        CreateBlankImage(instance.hwcomposer_pmem_path(), 2 /* mb */, "none");
+      }
       if (FileExists(instance.pstore_path())) {
         CreateBlankImage(instance.pstore_path(), 2 /* mb */, "none");
       }
diff --git a/host/commands/cvd/server.cc b/host/commands/cvd/server.cc
index 1c5b2ea..de1a3d7 100644
--- a/host/commands/cvd/server.cc
+++ b/host/commands/cvd/server.cc
@@ -462,9 +462,6 @@
         // across changes to config file format (within server.h major version).
         auto config = CuttlefishConfig::GetFromFile(*config_path);
         if (config) {
-          WriteAll(out, "Group:\n");
-          WriteAll(out, "  Assembly dir: " + assembly_dir + "\n");
-          WriteAll(out, "  Instances:\n");
           for (const std::string& instance_name : config->instance_names()) {
             Command command(assembly_info.host_binaries_dir + kStatusBin);
             command.AddParameter("--print");
diff --git a/host/commands/run_cvd/launch.cc b/host/commands/run_cvd/launch.cc
index ab5085d..6141e77 100644
--- a/host/commands/run_cvd/launch.cc
+++ b/host/commands/run_cvd/launch.cc
@@ -397,6 +397,8 @@
     std::vector<std::string> fifo_paths = {
         instance_.PerInstanceInternalPath("gnsshvc_fifo_vm.in"),
         instance_.PerInstanceInternalPath("gnsshvc_fifo_vm.out"),
+        instance_.PerInstanceInternalPath("locationhvc_fifo_vm.in"),
+        instance_.PerInstanceInternalPath("locationhvc_fifo_vm.out"),
     };
     for (const auto& path : fifo_paths) {
       unlink(path.c_str());
diff --git a/host/commands/run_cvd/server_loop.cpp b/host/commands/run_cvd/server_loop.cpp
index 3beb1d5..78316bc 100644
--- a/host/commands/run_cvd/server_loop.cpp
+++ b/host/commands/run_cvd/server_loop.cpp
@@ -164,6 +164,8 @@
         instance_.PerInstanceInternalPath("bt_fifo_vm.out"),
         instance_.PerInstanceInternalPath("gnsshvc_fifo_vm.in"),
         instance_.PerInstanceInternalPath("gnsshvc_fifo_vm.out"),
+        instance_.PerInstanceInternalPath("locationhvc_fifo_vm.in"),
+        instance_.PerInstanceInternalPath("locationhvc_fifo_vm.out"),
     };
     for (const auto& pipe : pipes) {
       unlink(pipe.c_str());
@@ -180,6 +182,10 @@
     unlink(kregistry_path.c_str());
     CreateBlankImage(kregistry_path, 2 /* mb */, "none");
 
+    auto hwcomposer_pmem_path = instance_.hwcomposer_pmem_path();
+    unlink(hwcomposer_pmem_path.c_str());
+    CreateBlankImage(hwcomposer_pmem_path, 2 /* mb */, "none");
+
     auto pstore_path = instance_.pstore_path();
     unlink(pstore_path.c_str());
     CreateBlankImage(pstore_path, 2 /* mb */, "none");
diff --git a/host/commands/status/main.cc b/host/commands/status/main.cc
index d50aaff..f602a3f 100644
--- a/host/commands/status/main.cc
+++ b/host/commands/status/main.cc
@@ -132,6 +132,7 @@
 
   if (print) {
     Json::Value device_info;
+    device_info["assembly_dir"] = config->assembly_dir();
     device_info["instance_name"] = instance.instance_name();
     device_info["instance_dir"] = instance.instance_dir();
     device_info["web_access"] =
diff --git a/host/libs/config/cuttlefish_config.h b/host/libs/config/cuttlefish_config.h
index e312e97..1729866 100644
--- a/host/libs/config/cuttlefish_config.h
+++ b/host/libs/config/cuttlefish_config.h
@@ -443,6 +443,8 @@
 
     std::string access_kregistry_path() const;
 
+    std::string hwcomposer_pmem_path() const;
+
     std::string pstore_path() const;
 
     std::string console_path() const;
diff --git a/host/libs/config/cuttlefish_config_instance.cpp b/host/libs/config/cuttlefish_config_instance.cpp
index 91a4bd6..4f1dd33 100644
--- a/host/libs/config/cuttlefish_config_instance.cpp
+++ b/host/libs/config/cuttlefish_config_instance.cpp
@@ -136,6 +136,10 @@
   return AbsolutePath(PerInstancePath("access-kregistry"));
 }
 
+std::string CuttlefishConfig::InstanceSpecific::hwcomposer_pmem_path() const {
+  return AbsolutePath(PerInstancePath("hwcomposer-pmem"));
+}
+
 std::string CuttlefishConfig::InstanceSpecific::pstore_path() const {
   return AbsolutePath(PerInstancePath("pstore"));
 }
diff --git a/host/libs/vm_manager/crosvm_manager.cpp b/host/libs/vm_manager/crosvm_manager.cpp
index 9e146a5..676689e 100644
--- a/host/libs/vm_manager/crosvm_manager.cpp
+++ b/host/libs/vm_manager/crosvm_manager.cpp
@@ -211,9 +211,15 @@
   }
 
   bool is_arm = HostArch() == Arch::Arm || HostArch() == Arch::Arm64;
-  if (!is_arm && FileExists(instance.access_kregistry_path())) {
-    crosvm_cmd.Cmd().AddParameter("--rw-pmem-device=",
-                                  instance.access_kregistry_path());
+  if (!is_arm) {
+    if (FileExists(instance.access_kregistry_path())) {
+      crosvm_cmd.Cmd().AddParameter("--rw-pmem-device=",
+                                    instance.access_kregistry_path());
+    }
+    if (FileExists(instance.hwcomposer_pmem_path())) {
+      crosvm_cmd.Cmd().AddParameter("--rw-pmem-device=",
+                                    instance.hwcomposer_pmem_path());
+    }
   }
 
   if (FileExists(instance.pstore_path())) {
@@ -313,8 +319,13 @@
     crosvm_cmd.AddHvcReadWrite(
         instance.PerInstanceInternalPath("gnsshvc_fifo_vm.out"),
         instance.PerInstanceInternalPath("gnsshvc_fifo_vm.in"));
+    crosvm_cmd.AddHvcReadWrite(
+        instance.PerInstanceInternalPath("locationhvc_fifo_vm.out"),
+        instance.PerInstanceInternalPath("locationhvc_fifo_vm.in"));
   } else {
-    crosvm_cmd.AddHvcSink();
+    for (auto i = 0; i < 2; i++) {
+      crosvm_cmd.AddHvcSink();
+    }
   }
 
   for (auto i = 0; i < VmManager::kMaxDisks - disk_num; i++) {
diff --git a/host/libs/vm_manager/qemu_manager.cpp b/host/libs/vm_manager/qemu_manager.cpp
index 1f38502..9fb1554 100644
--- a/host/libs/vm_manager/qemu_manager.cpp
+++ b/host/libs/vm_manager/qemu_manager.cpp
@@ -274,6 +274,14 @@
         << access_kregistry_size_bytes << ") not a multiple of 1MB";
   }
 
+  auto hwcomposer_pmem_size_bytes = 0;
+  if (FileExists(instance.hwcomposer_pmem_path())) {
+    hwcomposer_pmem_size_bytes = FileSize(instance.hwcomposer_pmem_path());
+    CHECK((hwcomposer_pmem_size_bytes & (1024 * 1024 - 1)) == 0)
+        << instance.hwcomposer_pmem_path() << " file size ("
+        << hwcomposer_pmem_size_bytes << ") not a multiple of 1MB";
+  }
+
   auto pstore_size_bytes = 0;
   if (FileExists(instance.pstore_path())) {
     pstore_size_bytes = FileSize(instance.pstore_path());
@@ -306,7 +314,8 @@
 
   qemu_cmd.AddParameter("-m");
   auto maxmem = config.memory_mb() +
-                access_kregistry_size_bytes / 1024 / 1024 +
+                (access_kregistry_size_bytes / 1024 / 1024) +
+                (hwcomposer_pmem_size_bytes / 1024 / 1024) +
                 (is_arm ? 0 : pstore_size_bytes / 1024 / 1024);
   auto slots = is_arm ? "" : ",slots=2";
   qemu_cmd.AddParameter("size=", config.memory_mb(), "M",
@@ -400,8 +409,11 @@
 
   if (config.enable_gnss_grpc_proxy()) {
     add_hvc(instance.PerInstanceInternalPath("gnsshvc_fifo_vm"));
+    add_hvc(instance.PerInstanceInternalPath("locationhvc_fifo_vm"));
   } else {
-    add_hvc_sink();
+    for (auto i = 0; i < 2; i++) {
+      add_hvc_sink();
+    }
   }
 
   auto disk_num = instance.virtual_disk_paths().size();
@@ -456,14 +468,29 @@
 
   // QEMU does not implement virtio-pmem-pci for ARM64 yet; restore this
   // when the device has been added
-  if (!is_arm && access_kregistry_size_bytes > 0) {
-    qemu_cmd.AddParameter("-object");
-    qemu_cmd.AddParameter("memory-backend-file,id=objpmem1,share=on,mem-path=",
-                          instance.access_kregistry_path(), ",size=",
-                          access_kregistry_size_bytes);
+  if (!is_arm) {
+    if (access_kregistry_size_bytes > 0) {
+      qemu_cmd.AddParameter("-object");
+      qemu_cmd.AddParameter(
+          "memory-backend-file,id=objpmem1,share=on,mem-path=",
+          instance.access_kregistry_path(),
+          ",size=", access_kregistry_size_bytes);
 
-    qemu_cmd.AddParameter("-device");
-    qemu_cmd.AddParameter("virtio-pmem-pci,disable-legacy=on,memdev=objpmem1,id=pmem0");
+      qemu_cmd.AddParameter("-device");
+      qemu_cmd.AddParameter(
+          "virtio-pmem-pci,disable-legacy=on,memdev=objpmem1,id=pmem0");
+    }
+    if (hwcomposer_pmem_size_bytes > 0) {
+      qemu_cmd.AddParameter("-object");
+      qemu_cmd.AddParameter(
+          "memory-backend-file,id=objpmem2,share=on,mem-path=",
+          instance.hwcomposer_pmem_path(),
+          ",size=", hwcomposer_pmem_size_bytes);
+
+      qemu_cmd.AddParameter("-device");
+      qemu_cmd.AddParameter(
+          "virtio-pmem-pci,disable-legacy=on,memdev=objpmem2,id=pmem1");
+    }
   }
 
   qemu_cmd.AddParameter("-object");
diff --git a/host/libs/vm_manager/vm_manager.h b/host/libs/vm_manager/vm_manager.h
index 4944f69..7a81a97 100644
--- a/host/libs/vm_manager/vm_manager.h
+++ b/host/libs/vm_manager/vm_manager.h
@@ -37,7 +37,7 @@
   // need to consume host resources, except for the PCI ID. Use this trick to
   // keep the number of PCI IDs assigned constant for all flags/vm manager
   // combinations
-  static const int kDefaultNumHvcs = 7;
+  static const int kDefaultNumHvcs = 8;
 
   // This is the number of virtual disks (block devices) that should be
   // configured by the VmManager. Related to the description above regarding
diff --git a/shared/config/init.vendor.rc b/shared/config/init.vendor.rc
index 24b0962..5d3b4bb 100644
--- a/shared/config/init.vendor.rc
+++ b/shared/config/init.vendor.rc
@@ -89,6 +89,7 @@
     start socket_vsock_proxy
     setprop ro.hardware.audio.primary goldfish
     symlink /dev/hvc6 /dev/gnss0
+    symlink /dev/hvc7 /dev/gnss1
 
 on property:sys.boot_completed=1
     trigger sys-boot-completed-set
diff --git a/shared/config/ueventd.rc b/shared/config/ueventd.rc
index 1e51a82..048bb8c 100644
--- a/shared/config/ueventd.rc
+++ b/shared/config/ueventd.rc
@@ -9,6 +9,9 @@
 # resume-on-reboot
 /dev/block/pmem0 0770 system system
 
+# hwcomposer
+/dev/block/pmem1 0770 system system
+
 # vtpm
 /dev/tpm0 0000 root root
 /dev/tpmrm0 000 system system
@@ -26,9 +29,12 @@
 /dev/hvc5 0660 bluetooth bluetooth
 /dev/vhci 0660 bluetooth bluetooth
 
-# gnss hal can access hvc6 in addition to gnss0
+# gnss hal can access hvc6/hvc7
 /dev/hvc6 0666 system system
+/dev/hvc7 0666 system system
+# gnss0/gnss1 are symlinks of hvc6/hvc7
 /dev/gnss0 0666 system system
+/dev/gnss1 0666 system system
 
 # Factory Reset Protection
 /dev/block/by-name/frp 0660 system system
diff --git a/shared/device.mk b/shared/device.mk
index d35227d..7c5d210 100644
--- a/shared/device.mk
+++ b/shared/device.mk
@@ -110,6 +110,7 @@
     persist.sys.zram_enabled=1 \
     ro.hardware.keystore_desede=true \
     ro.rebootescrow.device=/dev/block/pmem0 \
+    ro.vendor.hwcomposer.pmem=/dev/block/pmem1 \
     ro.incremental.enable=1 \
     debug.c2.use_dmabufheaps=1 \
     ro.camerax.extensions.enabled=true \
@@ -183,7 +184,7 @@
     vsoc_input_service \
     vtpm_manager \
 
-$(call soong_config_append, cvd, launch_configs, cvd_config_auto.json cvd_config_phone.json cvd_config_tablet.json cvd_config_tv.json)
+$(call soong_config_append, cvd, launch_configs, cvd_config_auto.json cvd_config_foldable.json cvd_config_phone.json cvd_config_tablet.json cvd_config_tv.json)
 $(call soong_config_append, cvd, grub_config, grub.cfg)
 
 #
diff --git a/shared/phone/device_vendor.mk b/shared/phone/device_vendor.mk
index 2f5fda0..84b813a 100644
--- a/shared/phone/device_vendor.mk
+++ b/shared/phone/device_vendor.mk
@@ -57,7 +57,7 @@
 
 # Runtime Resource Overlays
 ifeq ($(LOCAL_PREFER_VENDOR_APEX),true)
-PRODUCT_PACKAGES += com.google.aosp_cf_x86_64_phone.rros
+PRODUCT_PACKAGES += com.google.aosp_cf_phone.rros
 else
 PRODUCT_PACKAGES += cuttlefish_phone_overlay_frameworks_base_core
 endif
diff --git a/shared/sepolicy/vendor/file_contexts b/shared/sepolicy/vendor/file_contexts
index 69ed74f..31a1da0 100644
--- a/shared/sepolicy/vendor/file_contexts
+++ b/shared/sepolicy/vendor/file_contexts
@@ -15,6 +15,7 @@
 /dev/block/by-name/frp  u:object_r:frp_block_device:s0
 
 /dev/block/pmem0  u:object_r:rebootescrow_device:s0
+/dev/block/pmem1  u:object_r:hal_graphics_composer_pmem_device:s0
 /dev/block/zram0  u:object_r:swap_block_device:s0
 /dev/dri u:object_r:gpu_device:s0
 /dev/dri/card0  u:object_r:graphics_device:s0
@@ -28,9 +29,11 @@
 
 /dev/vhci  u:object_r:bt_device:s0
 
-# gnss hal can also read/write from hvc6
-# /dev/hvc6  u:object_r:serial_device:s0
+# gnss hal can also read/write from hvc6 and hvc7
+# hvc6 for gnss raw measurement
+# hvc7 for fixed location
 /dev/hvc6  u:object_r:gnss_device:s0
+/dev/hvc7  u:object_r:gnss_device:s0
 
 # ARM serial console device
 /dev/ttyAMA[0-9]*  u:object_r:serial_device:s0
diff --git a/shared/sepolicy/vendor/genfs_contexts b/shared/sepolicy/vendor/genfs_contexts
index a62ae44..dfb3f0b 100644
--- a/shared/sepolicy/vendor/genfs_contexts
+++ b/shared/sepolicy/vendor/genfs_contexts
@@ -7,6 +7,7 @@
 genfscon sysfs $1/0000:00:eval($2 + 1, 16, 2).0/virtio`'eval($3 + 1)`'/block u:object_r:sysfs_devices_block:s0 # vdb
 genfscon sysfs $1/0000:00:eval($2 + 2, 16, 2).0/virtio`'eval($3 + 2)`'/block u:object_r:sysfs_devices_block:s0 # vdc
 genfscon sysfs $1/0000:00:eval($2 + 3, 16, 2).0/virtio`'eval($3 + 3)`'/ndbus0 u:object_r:sysfs_devices_block:s0 # pmem0
+genfscon sysfs $1/0000:00:eval($2 + 4, 16, 2).0/virtio`'eval($3 + 3)`'/ndbus0 u:object_r:sysfs_devices_block:s0 # pmem1
 dnl')dnl
 dnl
 dnl # $1 = pci prefix
@@ -29,8 +30,8 @@
 dnl')dnl
 dnl
 # crosvm (x86)
-cf_pci_block_device(/devices/pci0000:00, 0x7, 8)
-cf_pci_gpu_device(/devices/pci0000:00, 0x15)
+cf_pci_block_device(/devices/pci0000:00, 0x7, 9)
+cf_pci_gpu_device(/devices/pci0000:00, 0x16)
 ## find /sys/devices/platform/* -type d -name 'rtc[0-9]' | sed 's,/rtc[0-9],,'
 genfscon sysfs /devices/platform/rtc_cmos/rtc u:object_r:sysfs_rtc:s0
 ## find /sys/devices/platform/* -type d -name 'wakeup[0-9]'
@@ -45,32 +46,32 @@
 genfscon sysfs /devices/virtual/mac80211_hwsim/hwsim1/net u:object_r:sysfs_net:s0
 
 # crosvm (arm64)
-cf_pci_block_device(/devices/platform/10000.pci, 0x7, 7)
-cf_pci_gpu_device(/devices/platform/10000.pci/pci0000:00, 0x13)
+cf_pci_block_device(/devices/platform/10000.pci, 0x7, 8)
+cf_pci_gpu_device(/devices/platform/10000.pci/pci0000:00, 0x14)
 ## find /sys/devices/platform/* -type d -name 'rtc[0-9]' | sed 's,/rtc[0-9],,'
 genfscon sysfs /devices/platform/2000.rtc/rtc u:object_r:sysfs_rtc:s0
 ## find /sys/devices/platform/* -type d -name 'wakeup[0-9]'
 ## arm64 2000.rtc on crosvm does not currently expose a wakeup node
 
 # qemu (x86)
-cf_pci_block_device(/devices/pci0000:00, 0x8, 7)
-cf_pci_gpu_device(/devices/pci0000:00, 0x14)
+cf_pci_block_device(/devices/pci0000:00, 0x8, 8)
+#cf_pci_gpu_device(/devices/pci0000:00, 0x16) - duplicated with crosvm(x86)
 ## find /sys/devices/platform/* -type d -name 'rtc[0-9]' | sed 's,/rtc[0-9],,'
 genfscon sysfs /devices/pnp0/00:04/rtc u:object_r:sysfs_rtc:s0
 ## find /sys/devices/platform/* -type d -name 'wakeup[0-9][0-9]'
 cf_rtc_wakeup_alarmtimer(/devices/pnp0/00:04, 0, 19)
 
 # qemu (arm64)
-cf_pci_block_device(/devices/platform/4010000000.pcie/pci0000:00, 0x7, 7)
-cf_pci_gpu_device(/devices/platform/4010000000.pcie/pci0000:00, 0x13)
+cf_pci_block_device(/devices/platform/4010000000.pcie/pci0000:00, 0x7, 8)
+cf_pci_gpu_device(/devices/platform/4010000000.pcie/pci0000:00, 0x14)
 ## find /sys/devices/platform/* -type d -name 'rtc[0-9]' | sed 's,/rtc[0-9],,'
 genfscon sysfs /devices/platform/9010000.pl031/rtc u:object_r:sysfs_rtc:s0
 ## find /sys/devices/platform/* -type d -name 'wakeup[0-9]'
 cf_rtc_wakeup_alarmtimer(/devices/platform/9010000.pl031, 0, 0)
 
 # qemu (arm)
-cf_pci_block_device(/devices/platform/3f000000.pcie/pci0000:00, 0x7, 7)
-cf_pci_gpu_device(/devices/platform/3f000000.pcie/pci0000:00, 0x13)
+cf_pci_block_device(/devices/platform/3f000000.pcie/pci0000:00, 0x7, 8)
+cf_pci_gpu_device(/devices/platform/3f000000.pcie/pci0000:00, 0x14)
 genfscon sysfs /devices/platform/rtc-test.1/wakeup/wakeup2 u:object_r:sysfs_wakeup:s0
 genfscon sysfs /devices/platform/rtc-test.2/wakeup/wakeup3 u:object_r:sysfs_wakeup:s0
 
diff --git a/shared/sepolicy/vendor/hal_graphics_composer.te b/shared/sepolicy/vendor/hal_graphics_composer.te
index cda5fdf..d08af30 100644
--- a/shared/sepolicy/vendor/hal_graphics_composer.te
+++ b/shared/sepolicy/vendor/hal_graphics_composer.te
@@ -3,3 +3,9 @@
 gpu_access(hal_graphics_composer_server)
 
 get_prop(hal_graphics_composer_server, vendor_cuttlefish_config_server_port_prop)
+get_prop(hal_graphics_composer_server, vendor_hwcomposer_prop)
+
+# Persistent memory for some hwcomposer configuration.
+type hal_graphics_composer_pmem_device, dev_type;
+allow hal_graphics_composer_server hal_graphics_composer_pmem_device:blk_file rw_file_perms;
+allow hal_graphics_composer_server block_device:dir search;
diff --git a/shared/sepolicy/vendor/property.te b/shared/sepolicy/vendor/property.te
index 679941b..9d91ad9 100644
--- a/shared/sepolicy/vendor/property.te
+++ b/shared/sepolicy/vendor/property.te
@@ -1,3 +1,4 @@
 vendor_restricted_prop(vendor_cuttlefish_config_server_port_prop)
 vendor_internal_prop(vendor_modem_simulator_ports_prop)
 vendor_internal_prop(vendor_boot_security_patch_level_prop)
+vendor_internal_prop(vendor_hwcomposer_prop)
diff --git a/shared/sepolicy/vendor/property_contexts b/shared/sepolicy/vendor/property_contexts
index 9369d44..f5688fb 100644
--- a/shared/sepolicy/vendor/property_contexts
+++ b/shared/sepolicy/vendor/property_contexts
@@ -14,3 +14,4 @@
 ro.vendor.boot_security_patch u:object_r:vendor_boot_security_patch_level_prop:s0
 vendor.bt.rootcanal_mac_address  u:object_r:vendor_bt_rootcanal_prop:s0
 vendor.bt.rootcanal_test_console  u:object_r:vendor_bt_rootcanal_prop:s0
+ro.vendor.hwcomposer.pmem  u:object_r:vendor_hwcomposer_prop:s0 exact string
diff --git a/shared/sepolicy/vendor/vendor_init.te b/shared/sepolicy/vendor/vendor_init.te
index 5bddb14..6a01641 100644
--- a/shared/sepolicy/vendor/vendor_init.te
+++ b/shared/sepolicy/vendor/vendor_init.te
@@ -5,6 +5,7 @@
 }:chr_file { getattr };
 
 set_prop(vendor_init, vendor_bt_rootcanal_prop)
+set_prop(vendor_init, vendor_hwcomposer_prop)
 
 get_prop(vendor_init, vendor_graphics_config_prop)
 
diff --git a/vsoc_x86_64/phone/aosp_cf.mk b/vsoc_x86_64/phone/aosp_cf.mk
index 69f1f9a..59c1644 100644
--- a/vsoc_x86_64/phone/aosp_cf.mk
+++ b/vsoc_x86_64/phone/aosp_cf.mk
@@ -50,7 +50,7 @@
 
 # Exclude features that are not available on AOSP devices.
 ifeq ($(LOCAL_PREFER_VENDOR_APEX),true)
-PRODUCT_PACKAGES += com.google.aosp_cf_x86_64_phone.hardware.core_permissions
+PRODUCT_PACKAGES += com.google.aosp_cf_phone.hardware.core_permissions
 else
 PRODUCT_COPY_FILES += \
     frameworks/native/data/etc/aosp_excluded_hardware.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/aosp_excluded_hardware.xml
diff --git a/vsoc_x86_64/phone/aosp_cf_foldable.mk b/vsoc_x86_64/phone/aosp_cf_foldable.mk
index 9c4abbb..96c2c59 100644
--- a/vsoc_x86_64/phone/aosp_cf_foldable.mk
+++ b/vsoc_x86_64/phone/aosp_cf_foldable.mk
@@ -24,7 +24,5 @@
     device/google/cuttlefish/shared/foldable/device_state_configuration.xml:$(TARGET_COPY_OUT_VENDOR)/etc/devicestate/device_state_configuration.xml
 # Include RRO settings that specify the fold states and screen information.
 DEVICE_PACKAGE_OVERLAYS += device/google/cuttlefish/shared/foldable/overlay
-# Include the foldable `launch_cvd --config foldable` option.
-$(call soong_config_append,cvd, launch_configs, cvd_config_foldable.json)
 # Include the android-info.txt that specifies the foldable --config by default.
 TARGET_BOARD_INFO_FILE := device/google/cuttlefish/shared/foldable/android-info.txt